Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 4 years ago.
Improve this question
BasicAuthenticationFilter while checking for existing authentication matches based on the username only. so if incoming request send correct username and incorrect password , the user is still considered already authenticated. Is this a desired behavior ? doesnt seem correct to me .any views ?
////////////////////
private boolean authenticationIsRequired(String username) {
// Only reauthenticate if username doesn't match SecurityContextHolder and user
// isn't authenticated
// (see SEC-53)
Authentication existingAuth = SecurityContextHolder.getContext()
.getAuthentication();
if (existingAuth == null || !existingAuth.isAuthenticated()) {
return true;
}
// Limit username comparison to providers which use usernames (ie
// UsernamePasswordAuthenticationToken)
// (see SEC-348)
if (existingAuth instanceof UsernamePasswordAuthenticationToken
&& !existingAuth.getName().equals(username)) {
return true;
}
as it looks in SecurityContextHolder.getContext().getAuthentication(); it means that the client already has the JSESSION cookie, so it has been already authenticated with username and password.
Checking password one more time will make this method worthless as it lead to redo all the authentication process (retrieving password from database, compare it...) and I guess it has been written to avoid it. Besides password is not stored in SecurityContextHolder context
A potential security breach could occur on CRSF attack but spring-security provides protection against this one. see spring-security csrf
Related
I separate my application into 2 parts:
Front end : Vue js and connected with AWS congnito for login feature (email/pw or google social login).
Back end : Spring boot Restful. User information stored in database (a unique id from congnito as primary key.)
My flow of authentication
User redirected to congnito and login. congnito will return a unique id and JWT.
Front end passes the unique id and JWT to back end controller.
backend validate JWT and return user information from DB
My question is:
Is this a bad practice to authenticate on front end and pass data to back end for spring security? If so, may I have any suggestion to change my implementation flow?
To call AuthenticationProvider.authenticate, a Authentication consist username (in my case, the unique id from cognito) and password is needed (UsernamePasswordAuthenticationToken). Are there any implementation to set only username? or it is fine to set password as empty string?
// controller
public String login(HttpServletRequest req, String cognitoId, String jwt) {
// check JWT with AWS
if(!AwsJwtChecker(cognitoId, jwt))
return createErrorResponseJson("invalid jwt");
UsernamePasswordAuthenticationToken authReq
= new UsernamePasswordAuthenticationToken(cognitoId, "");
Authentication auth = authManager.authenticate(authReq);
SecurityContext sc = SecurityContextHolder.getContext();
sc.setAuthentication(auth);
HttpSession session = req.getSession(true);
session.setAttribute(SPRING_SECURITY_CONTEXT_KEY, sc);
MyUser user = userRepository.selectUserByCognitoId(cognitoId);
return createLoginSuccessResponse(user);
}
// web config
#Component
public class CustomAuthenticationProvider implements AuthenticationProvider {
#Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
String cognitoId = authentication.getName();
// check user exist in db or not
MyUser user = userRepository.selectUserByCognitoId(cognitoId);
if (user != null) {
return new UsernamePasswordAuthenticationToken(username, "", user.getRoles());
} else {
throw new BadCredentialsException("Authentication failed");
}
}
#Override
public boolean supports(Class<?>aClass) {
return aClass.equals(UsernamePasswordAuthenticationToken.class);
}
}
Is this a bad practice to authenticate on front end and pass data to back end for spring security? If so, may I have any suggestion to change my implementation flow?
No, in fact it's best practice. JWT is exactly for that purpose: You can store information about the user and because of the signature of the token, you can be certain, that the information is trustworthy.
You don't describe what you are saving in the database, but from my perspective, you are mixing two authentication methods. While it's not forbidden, it might be unnecessary. Have you analysed your token with jwt.io? There are many information about the user within the token and more can be added.
Cognito is limited in some ways, like number of groups, but for a basic application it might be enough. It has a great API to manage users from within your application, like adding groups or settings properties.
You don't describe what you do with the information that is returned with 3). Vue can too use the information stored in the jwt to display a username or something like that. You can decode the token with the jwt-decode library, eg, and get an object with all information.
To call AuthenticationProvider.authenticate...
Having said that, my answer to your second question is: You don't need the whole authentication part in you login method.
// controller
public String login(HttpServletRequest req, String cognitoId, String jwt) {
// check JWT with AWS
if(!AwsJwtChecker(cognitoId, jwt))
return createErrorResponseJson("invalid jwt");
return userRepository.selectUserByCognitoId(cognitoId);
}
This should be completely enough, since you already validate the token. No need to authenticate the user again. When spring security is set up correctly, the jwt will be set in the SecurityContext automatically.
The problem I see with your implementation is that anyone could send a valid jwt and a random cognitoId and receive user information from the database. So it would be better to parse the jwt and use something from within the jwt, like username, as identifier in the database. The token can't be manipulated, otherwise the validation fails.
public String login(String jwt) {
// check JWT with AWS
if(!AwsJwtChecker(jwt))
return createErrorResponseJson("invalid jwt");
String identifier = getIdentifier(jwt);
return userRepository.selectUserByIdentifier(identifier);
}
Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 4 years ago.
Improve this question
BasicAuthenticationFilter while checking for existing authentication matches based on the username only. so if incoming request send correct username and incorrect password , the user is still considered already authenticated. Is this a desired behavior ? doesnt seem correct to me .any views ?
////////////////////
private boolean authenticationIsRequired(String username) {
// Only reauthenticate if username doesn't match SecurityContextHolder and user
// isn't authenticated
// (see SEC-53)
Authentication existingAuth = SecurityContextHolder.getContext()
.getAuthentication();
if (existingAuth == null || !existingAuth.isAuthenticated()) {
return true;
}
// Limit username comparison to providers which use usernames (ie
// UsernamePasswordAuthenticationToken)
// (see SEC-348)
if (existingAuth instanceof UsernamePasswordAuthenticationToken
&& !existingAuth.getName().equals(username)) {
return true;
}
as it looks in SecurityContextHolder.getContext().getAuthentication(); it means that the client already has the JSESSION cookie, so it has been already authenticated with username and password.
Checking password one more time will make this method worthless as it lead to redo all the authentication process (retrieving password from database, compare it...) and I guess it has been written to avoid it. Besides password is not stored in SecurityContextHolder context
A potential security breach could occur on CRSF attack but spring-security provides protection against this one. see spring-security csrf
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 5 years ago.
Improve this question
As a low level developer, I am working on a project on User Management using ASP.NET Identity in ASP.NET mvc.
Please how do I do the following:
Automatically lock the user after 5 failed login attempt.
Manually unlock the user by the Admin after a request.
Send e-mail to selected users based on role or even all users
How do I use the ASP.NET Identity in MVC to write the code for the user interface.
Thanks
You can set MaxFailedAccessAttemptsBeforeLockout=5 as in below. you can find this at
IdentityConfig.cs
manager.MaxFailedAccessAttemptsBeforeLockout = 5;
And you can set shouldLockout equal to true in login then it makes lockout in 5 times.
await `SignInManager.PasswordSignInAsync(model.Email, model.Password, model.RememberMe, shouldLockout: true);`
you can see below code in
Identityconfig.cs
manager.DefaultAccountLockoutTimeSpan = TimeSpan.FromMinutes(5);
According to the minutes, you set, will generate timestamp on AspNetUsers table LockoutEndDateUtc column.According to setup time, you can edit the time backward 5 minutes as in this scenario.You can do this using an interface for the particular requester querying by userid and modify LockoutEndDateUtc respectively.
3.Your roles are store in AspNetRoles table and users map their roles with AspnetUserRoles table. You can query particular roles and retrieve users mail address. Set up the mail server for sending emails.
here is code for setup Gmail
var SenderEmail = new MailAddress("sendermail", "");
var ReciverEmail = new MailAddress("Destinationmail", "");
var Password = "";
var subject = "";
var body = message.Body;
var smtp = new SmtpClient
{
Host = "smtp.gmail.com",
Port = 587,
EnableSsl = true,
DeliveryMethod = SmtpDeliveryMethod.Network,
UseDefaultCredentials = false,
Credentials = new NetworkCredential(SenderEmail.Address, Password)
};
using (var mess = new MailMessage(SenderEmail, ReciverEmail)
{
Subject = "",
Body = ""
})
{
smtp.Send(mess);
}
I've a oauth2 resource server which uses the JwtBearerMiddleware to validate the access tokens. Now I wan't that the access token is invalid if the security stamp has changed. As it looks like this middleware doesn't validate the security stamp by itself.
I've found the SecurityStampValidator class which only seems to validate cookie authentication.
Where and how do I have to validate the security stamp from my json web token?
My current way to do it is to register an eventhandler for the OnTokenValidated event when I register the JwtBearerMiddleware. In this eventhandler I simply query the database for the security claim and compare it with the one in the token. When the security stamp isn't the same I just set the Ticket and SecurityToken of the context to null and skip to the next middleware which eventually will throw an 401 http status code if authentication is required.
app.UseJwtBearerAuthentication(new JwtBearerOptions
{
...
Events = new JwtBearerEvents
{
OnTokenValidated = async (ctx) =>
{
var securityStampClaim = ctx.Ticket.Principal.Claims.FirstOrDefault(claim => claim.Type == "AspNet.Identity.SecurityStamp");
var subjectClaim = ctx.Ticket.Principal.Claims.FirstOrDefault(claim => claim.Type == OpenIdConnectConstants.Claims.Subject);
if (securityStampClaim == null || subjectClaim == null)
return;
var user = await userStore.FindByIdAsync(subjectClaim.Value, ctx.HttpContext.RequestAborted);
if (user?.SecurityStamp == securityStampClaim.Value)
return;
ctx.SecurityToken = null;
ctx.Ticket = null;
ctx.SkipToNextMiddleware();
}
}
});
Is this how it should be done?
Is this how it should be done?
Technically, yes (you could even use SignInManager.ValidateSecurityStampAsync(principal) to simplify your code a bit).
That said, you should strongly consider avoiding storing the security stamps in your JWT tokens because they are not just "opaque" strings used to determine whether a token or a cookie should be considered as revoked, they are also used as the sole source of entropy by ASP.NET Core Identity to generate 2FA tokens: if you store them as-is in a JWT, they can be easily extracted by a malicious third-party client application and used to predict valid 2FA codes for the logged in user.
This is a known issue, but AFAIK, there's no plan to fix it: https://github.com/aspnet/Identity/issues/626.
If you want to store the security stamps in your access tokens, consider using OpenIddict's default (encrypted) format, which is exactly the same as the one used by ASP.NET Core for its encrypted authentication cookies.
I had a Posting on a blog about Sessions AND Cookies. Here are details
Sessions
Sessions are More Secure
Sessions are on the server
Cookies
Cookies are On client side
Less Secure
Once it is disable on browser the difficult to use.
On the basis of above argument i used sessions in Login system to keep UserId,UserName & roleName
Now on the the basis of roleName i will decide either this is Admin to enter to administrator section or not.
I have used this Code in Model in MVC
public bool LoginMe()
{
Int64 Error;
//create db
Database db = DatabaseFactory.CreateDatabase("DBContext");
DbCommand dbCommand = db.GetStoredProcCommand("ValidateUser");
db.AddInParameter(dbCommand, "#Username", DbType.String, this.UserName);
db.AddInParameter(dbCommand, "#Password", DbType.String, EncryptPassword(this.Password));
db.AddOutParameter(dbCommand, "#Error", DbType.Int64, 10);
DataSet dsResult = db.ExecuteDataSet(dbCommand);
Error = Convert.ToInt64(db.GetParameterValue(dbCommand, "#Error"));
if (Error == 1100)
{
try
{
var query = (from o in dsResult.Tables[0].AsEnumerable()
select new AllUser
{
UserId = o.Field<int>("UserId"),
UserName = o.Field<string>("UserName"),
roleName = o.Field<string>("roleName"),
}).Single(); // this will raise an exception if there isn't just one record returned
Session["UserId"] = query.UserId;
Session["UserName"] = query.UserName;
Session["roleName"] = query.roleName;
return true;
}
catch {
// do nothing and let method return false as something has gone wrong.
// add logging here if you are using it to show there has been a problem
}
}
return false;
}
I used it in View like #Session["UserId"]
Now an expert comment on this like
If you aren't using https and securing the session cookie then this might make it easy to hack your site, although that's the same for any session based site (nearly all of them)
It might be nice to add some check so that if you remove a user's rights, the session variables are deleted the next time that user requests something from the server,
otherwise they could carry on using the site even though their account it banned.You'd have to decide if this is likely and then how you want to do this (using an authorization filter maybe.)
Above comments confused me.Can any body make it clear?What is the best way to keep these information?
Session state uses client tickets to identify the server-side session, it may be susceptible to session ID spoofing and injection attacks.
So, to hack session values one would require hacking the remote-server.
And yes, for highly secure application(such as online banking) use https.
http://msdn.microsoft.com/en-us/magazine/cc163730.aspx#S9
Secure sockets layer (SSL) should be used to prevent network-level sniffing of session IDs, authentication tickets, application cookies, and other request/response information.
Can session value be hacked?
Use HTTPS if you application handles sensitive information(credit-card number,account num,passwords).
Store the User object (model with userId,username,role) in the session than separate attributes
Set setHttpOnly attribute for SESSION_ID.
It might be costly to refresh the User object stored in session before invoking every operation to reflect the current rights stored in database.