For the app types that handle user management (JWT, Session), how can I change the password policy to meet my specific needs?
The only common point where it would make sense to add password validation logic is in AccountResource#checkPasswordLength(String password)
private static boolean checkPasswordLength(String password) {
return !StringUtils.isEmpty(password) &&
password.length() >= ManagedUserVM.PASSWORD_MIN_LENGTH &&
password.length() <= ManagedUserVM.PASSWORD_MAX_LENGTH;
}
But this definitely does not seem like the correct place to do it.
Related
I implemented two factor authentication but by following this tutorial
https://learn.microsoft.com/en-us/aspnet/identity/overview/features-api/two-factor-authentication-using-sms-and-email-with-aspnet-identity
I want to make the code expire after single use.
Right now, user receives the same code during the expiration time (which is set to 5 minutes) completes. Is there a way to make the code single use? I couldn't find anything on this subject.
There is a note in the tutorial that you linked to that says:
The 2FA codes are generated using Time-based One-time Password Algorithm and codes are valid for six minutes. If you take more than six minutes to enter the code, you'll get an Invalid code error message.
So, using this method, you cannot make the code expire after user.
You could, as an addition, keep a store of codes that have been used and check against that store before validating the code. You could allow the codes to expire out of that store after 6 minutes, which is their natural expiry time, but in the meantime use them to reject a second authentication.
Alternatively, you can choose to avoid the TOTP method and generate a random code that you store against your user before you send the SMS or email. Then you can check against that code when the user authenticates with it and delete or invalidate the code at that point. Using TOTP means that you could extend this 2FA to use an authenticator app based flow for the authentication too, which is more secure than SMS or email.
AspNetIdentity does not automatically invalidate used second factor codes, a code is always valid for a six minute window, but there is a workaround for this.
One of the inputs to the token generator is the SecurityStamp, which is stored as part of the user account. Token providers that extend the TotpSecurityStampBasedTokenProvider, like for example the EmailTokenProvider, will use the security stamp when they generate and validate a second factor code.
Thus, you can invalidate all issued tokens by changing the security stamp by calling UserManager.UpdateSecurityStampAsync(userId) after a successful two factor authentication.
There is a side effect that may not be desirable, being that other sessions will get logged out when the security stamp changes.
In the ApplicationSignInManager class, you can override TwoFactorSignInAsync and make the call there:
(Note: This is taken from AspNetIdentity, if you are using a different package, make sure to take TwoFactorSignInAsync from that instead and modify it accordingly.)
public override async Task<SignInStatus> TwoFactorSignInAsync(string provider, string code, bool isPersistent, bool rememberBrowser)
{
var userId = await GetVerifiedUserIdAsync().WithCurrentCulture();
if (userId == null)
{
return SignInStatus.Failure;
}
var user = await UserManager.FindByIdAsync(userId).WithCurrentCulture();
if (user == null)
{
return SignInStatus.Failure;
}
if (await UserManager.IsLockedOutAsync(user.Id).WithCurrentCulture())
{
return SignInStatus.LockedOut;
}
if (await UserManager.VerifyTwoFactorTokenAsync(user.Id, provider, code).WithCurrentCulture())
{
// When token is verified correctly, clear the access failed count used for lockout
await UserManager.ResetAccessFailedCountAsync(user.Id).WithCurrentCulture();
// Update the security stamp in order to invalidate all issued two factor tokens.
await UserManager.UpdateSecurityStampAsync(user.Id);
await SignInAsync(user, isPersistent, rememberBrowser).WithCurrentCulture();
return SignInStatus.Success;
}
// If the token is incorrect, record the failure which also may cause the user to be locked out
await UserManager.AccessFailedAsync(user.Id).WithCurrentCulture();
return SignInStatus.Failure;
}
If you want only the latest issued code to be valid, you should make the call to UpdateSecurityStampAsync also before any new code is generated.
I am working on a Grails application that uses the excellent Spring Security Plugin. The authentication happens through Oracle Access Manager which protects the application URL. So I just use the PreAuth filter and never had to worry about passwords. Until now.
There is another application that we need to integrate with (that manages freezer Samples and need user access management so that user's don't see someone else's samples) and uses LDAP. The said application exposes an API that takes in a username password and returns data based that user's access (there is no on behalf of user feature).
The problem is that I need to ask users for their passwords and send plain text password to that service. So hashing and encoding needs to be reversible and I cannot just compare hashcodes. Any suggestions on how to manage this in the best way possible?
I was thinking of using a random salt created on server (and cycle that like every 6 hours), encode the password and set it in a short life cookie, and decode it on the server when making the call to the external service. This way a potential attacker will need data from server memory and the cookies from user's system and I don't store plain text password anywhere. Just a naive attempt. Very open to suggestions.
So I hacked one of my apps to work like this:
In the User class: (Spring Security User.groovy)
static transients = ['springSecurityService', 'rawPassword']
//To bypass facebook users who log in via facebook
//we will back up original hashed password string
//log them in then save old password has by calling user.rawPassword=oldHash
//this will update underlying password with string hash value
void setRawPassword(String p) {
password=p
}
Then in the relevant service
//Get old password hash
def oldPassword=user?.password
String authPassword
if (oldPassword) {
def uid = user.password + new UID().toString() + prng.nextLong() + System.currentTimeMillis()
MessageDigest digest = MessageDigest.getInstance("SHA-256");
byte[] hash = digest.digest(uid.getBytes("UTF-8"));
def token1 = hash.encodeBase64()
user.password = token1
//Generate a random password
authPassword = token1
//Update user Password to be random Password
UsernamePasswordAuthenticationToken uat1 = new UsernamePasswordAuthenticationToken(user.username, authPassword, null)
uat1.setDetails(user)
SecurityContext context = SecurityContextHolder.getContext()
//Re-setAuthentication of springSecurity using new Password
context.setAuthentication(uat1)
if (oldPassword) {
//Now we are authenticated let's set back the original Hash as the hash we collected in oldPassword
//just before doing the hack
user.rawPassword = oldPassword
user.save(flush: true)
}
springSecurityService.reauthenticate user.username
}
This is rather an ugly hack to authenticate as a user without changing their set password (in the end) during process changed and changed back again..
I am not recommending it but it may be an easier option than what you have outlined
I have two types of admin.
Super admin and normal admin.
Both start on the page admin.xhtml.
I want to forward super admin users to super-admin.xhtml and normal admin to normal-admin.xhtml.
How do I do this in JSF (I'm using Spring Security)?
I'm unfamiliar with JSF, but assuming it functions under the hood just like a Spring MVC JSP application, you can have your controller deliver a different page depending on the role(s) held by the user:
#RequestMapping("/admin.xhtml")
#PreAuthorize("hasAnyRole('ROLE_ADMIN', 'ROLE_SUPERADMIN')")
public String getAdminPage(Modelmap model, Principal principal) {
Collection<? extends GrantedAuthority> authorities = SecurityContextHolder.getContext().getAuthentication().getAuthorities();
for (GrantedAuthority authority : authorities) {
if (authority.toString() == "ROLE_SUPERADMIN") { return "superadminpage"; }
}
//no need to check for admin privileges, since the annotation took care of that
//if you're not using annotations (or #PostAuthorize), you'd have to capture the
//'admin' role as well, and adjust the return statements accordingly.
return "adminpage";
}
I have a question of how to better organize the implementation of the following functionality.
Suppose a user needs to be registered into the system by unique email and password (first step) and then he should confirm registration (second step). I have several choices of structuring implementation of first step (registration) between application services/domain services/user entity and I'm not sure which one is better.
First option:
AppService:
var existingUser = UserRepository.GetUserByEmail(email);
if (existingUser != null)
{
throw new ValidationException(...);
}
var newUser = UserFactory.CreateUser();
newUser.Register(email, password);
UserRepository.Save(newUser);
// commit
So here, we do not use any domain service. The thing which I personally don't feel confortable is that Email uniqueness business rule is checked in the Application Service, this being a business rule.
Second option:
AppService:
var user = UserRegistrationDomainService.RegisterUser(email, password);
UserRepository.Save(user);
// commit
UserRegistrationDomainService:
User RegisterUser(email, password)
{
var existingUser = UserRepository.GetUserByEmail(email);
if (existingUser != null)
{
throw new ValidationException(...);
}
var newUser = UserFactory.CreateUser();
newUser.Register(email, password);
return newUser;
}
What I don't like here, is that this solution is not quite symmetric with the implementation of second step, where we just get the user from repository and call User.ConfirmRegistration(). So for registration confirmation we do not need any domain service whereas for registration, in second option, we use such service.
Which option is better? Can the application service from first option contain email uniqueness validation?
Personally I think the Validation for that lives in the Domain (either the Entity of the service). The rule after all, is required due to a business rule.
It would be preferable in option 2 for the application services not to be responsible for saving the user, this is blurring the lines of responsibilities and it would be nicer if the domain service handled it. And the application service would simply call UserRegistrationDomainService.RegisterUser(email, password)
Option 1 means that the unique email rule is application-specific. In other words, if you take the Domain dll (or jar, module, etc.) to reuse it in another application, the rule won't be there any more.
Since we can reasonably consider that rule to be application-agnostic, I'd choose option 2.
Another solution could be to implement it in the Factory instead. After all, this is where you'll typically put the validation logic upon creation of your User (null/empty name checking, email format verification, and so on) so why not centralize all creation rules in the same place ?
I'm using the Acegi plugin in my Grails app. After a user registers, he is redirected to an action that is protected. Therefore, he is shown the login form.
However, I would prefer if the user was automatically logged in as soon as he completes registration. It seems like I could achieve this by redirecting to the action that the login form uses
redirect(uri:"/j_acegi_security_check?j_username=${username}&j_password=${passed}")
But this would send a HTTP request to the client (and back to the server) which shows the user's password. Is there a way I can login automatically in a secure fashion?
Thanks,
Don
If you generate the controller classes for the spring security plugin (grails generate-registration) you'll see the following lines in RegisterController which does just what you want:
class RegisterController {
def daoAuthenticationProvider
...
def save = {
...
def auth = new AuthToken(person.username, params.passwd)
def authtoken = daoAuthenticationProvider.authenticate(auth)
SecurityContextHolder.context.authentication = authtoken
redirect uri: '/'
}
Be sure that params.passwd is the plain-text password (i.e. not hashed) and it works like a charm.
I haven't tried this with non-test code, but this is the method that I created to log a user in within my integration tests (after building/saving the appropriate users/roles in my test setup):
import org.codehaus.groovy.grails.plugins.springsecurity.GrailsDaoAuthenticationProvider
import org.springframework.security.providers.UsernamePasswordAuthenticationToken
import org.springframework.security.context.SecurityContextHolder
...
def logInAsUser(username, password) {
daoAuthenticationProvider.getUserCache().removeUserFromCache(username)
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(username, password)
SecurityContextHolder.context.authentication = daoAuthenticationProvider.authenticate(token)
}
I construct and inject the authentication token in the security context. There might be a little more that you need to do to get your user logged in and past security, but this would be the start of whatever that is.
I'll actually need to do exactly what you're asking in a week or two for my current app, post back if you figure it out fully before I do :).
This is Burt Beckwith's answer (not mine)
(It was left as a comment by Burt, but I think it deserves to be more prominent)
If you don't have the password, you can load the user via
def user = User.findByUsername(username)
and setting the authority array in the 3-parameter constructor. Create the auths via
GrantedAuthority[] auths = user.authorities.collect { new GrantedAuthorityImpl(it.authority) }
Then you can omit the call to authenticate() and use:
SecurityContextHolder.context.authentication = new UsernamePasswordAuthenticationToken(username, 'unknown', auths)