I have developed an application with spring mvc for high user traffic. Suppose there is least 20,000 concurrent user. I have implemented spring security custom authentication provider in two ways.
1st one is :
#Override
public Authentication authenticate(Authentication authentication)
throws AuthenticationException {
String username = authentication.getName();
String password = authentication.getCredentials().toString();
CustomUser user = _userDetailService.loadUserByUsername(username);
if (user == null || !user.getUsername().equalsIgnoreCase(username)) {
throw new BadCredentialsException("Username not found.");
}
if (!BCrypt.checkpw(password, user.getPassword())) {
throw new BadCredentialsException("Wrong password.");
}
Collection < ? extends GrantedAuthority > authorities = user.getAuthorities();
return new UsernamePasswordAuthenticationToken(user, password, authorities);
}
2nd one is:
#Override
public Authentication authenticate(Authentication authentication)
throws AuthenticationException {
try {
Authentication auth = super.authenticate(authentication);
//if reach here, means login success, else an exception will be thrown
//reset the user_attempts
return auth;
} catch (BadCredentialsException e) {
//invalid login, update to user_attempts
throw e;
}
}
Now my question is whice implementation will give me the faster output?
As already pointed out by Afridi, your 1st version is exactly what DaoAuthenticationProvider is supposed to do. I would strongly discourage from re-implementing its functionality, since you might for example introduce new security relevant errors.
If you really need a custom authentication method, there is no way around a custom authentication method of course. In order to measure the performance of this implementation in general or versus the standard implementation, you should simply define a test scenario (e.g. 20000 dummy authentications as homlis83 suggested) and run the program in a profiler. This will how you exactly how much time is spent in you authentication method and even which part takes the most time.
I think the most popular Java profiler is VisualVM and depending on your IDE there might be a plugin that further simplifies its use. There are also a lot of tutorials for Java profiling out there, but this is definitvely the way to go for you to get reliable data for the performance.
Related
I am using the spring-boot mvc in my project and there is a strange issue that I am facing.
I have this method in my service layer
#Autowired
UserRepository userRepository;
public void registerUser(User user) {
User existingUser = userRepository.findByUsername(user.getUsername());
if (existingUser != null) {
throw new UserException("Sorry! This username is already taken");
}
// other validations
userRepository.save(user);
}
Surprisingly , there are entries into the database that have the same username. This happens when the the front-end POSTs multiple requests for the same form content.
I have two questions:
1 .Is there an option for me to stop this at the back-end (Java)in addtion to asking the front-end to disable the submit button after click?
Will it be a security risk if it is handled only on the front-end?
I am trying to figure out a clean and simple way to obtain the uid resulting from a call to createUser() when working with the Java SDK. This is easy to do when working with the Javascript SDK (e.g., this question/answer). I've also seen the question raised on Stackoverflow in the context of the Firebase iOS API where it apparently isn't so easy. My problem is how to do it using the Firebase Java SDK. Specifically, my use case is the same as that in the iOS-related question, i.e. allow an Admin user to create user accounts (email/password authentication) and also store other info about the created user in Firebase with the uid as the key. Knowing and using the uid as a key is essential in that it is the basis for the security rules.
I've seen a couple of proposed solutions, both of which involved some procedure to be carried out after the new user account has been created. These are
query the Firebase using the email address
Login as the new user and use the authData to get the uid
Either way I have a convoluted solution with multiple async callbacks to deal with an issue that is trivial when using the Javascript API.
I therefore have three specific questions:
Is there currently a better approach than the two I've listed above?
If I use the 2nd approach and login as the newly created user, doesn't that over-ride the Admin token (i.e., log-out the admin who created the user) which in turn means new security rules apply?
Is there any expectation that the Android & Java SDK's will be upgraded anytime soon so that the createUser() API is the same as the Javascript version?
UPDATE: Digging deeper and experimenting a bit I found the answers to my questions. It turns out that the API documentation provided by Firebase is out of date and/or inconsistent.
Re Q1: According to the Javadoc for createUser() the the only available callback handler is a Firebase.ResultHandler. However according to the Changelog, the API Reference document, and the documentation on Creating User Accounts, a Firebase.ValueResultHandler may be used as well. This provides direct access to the UID
Re Q2: The answer is yes. Authenticating the newly created user account results in the replacement of the auth token.
Re Q3: The real question should be "When are the Firebase folks going to update the Javadoc?" Or maybe a better question is "Why are new versions of the SDK being released without updated and accurate documentation?"
The following code is the correct way to deal with creating a new user
Firebase ref = new Firebase("https://<YOUR-FIREBASE>.firebaseio.com");
ref.createUser("harry#foo.com", "badPassword", new Firebase.ValueResultHandler<Map<String, Object>>() {
public void onSuccess(Map<String, Object> result) {
System.out.println("New account with uid: " + result.get("uid"));
}
public void onError(FirebaseError firebaseError) {
// there was an error
}
});
I've updated the question to explain the reasons.
Try this. This is for the newer version of Firebase that came out in the most recent Google I/O. I am not promoting this new version or putting the older version down. I am just stating this as an alternative to the solution above:
mAuth = FirebaseAuth.getInstance();
//creates the user with email and password...make this another type of login if you want
mAuth.createUserWithEmailAndPassword(mEmail, mPassword).addOnCompleteListener(signup.this, new OnCompleteListener<AuthResult>() {
#Override
public void onComplete(#NonNull Task<AuthResult> task) {
if (task.isSuccessful()) {
//do something
}
}
});
Now you can add an AuthStateListener. You will have to put code in the onCreate, onStart, and onStop methods. Note that the above code can go in any reasonable method (e.g. onCreate, onStart, onResume, etc.). Here we go:
FirebaseAuth mAuth;
FirebaseAuth.AuthStateListener mAuthListener;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_something);
mAuth = FirebaseAuth.getInstance();
mAuthListener = new FirebaseAuth.AuthStateListener() {
#Override
public void onAuthStateChanged(#NonNull FirebaseAuth firebaseAuth) {
FirebaseUser user = firebaseAuth.getCurrentUser();
if(user != null){
//check for null to prevent NullPointerException when dealing with user
if(!user.getUid().matches("")){
//make this check just in case...I've experienced unexplainable glitches here
String uid = user.getUid();
//do more stuff with Uid
}
}
}
}
}
#Override
public void onStart(){
super.onStart();
mAuth.addAuthStateListener(mAuthListener);
}
#Override
public void onStop(){
super.onStop();
if(mListener != null){
mAuth.removeAuthStateListener(mAuthListener);
}
}
In the end, what happens is, once the user is created (and signed in at the same time), the mAuthListener makes a callback (it executes whatever is inside the mAuthListener, which, in this case, is getting the user's UID and doing other stuff with it). If you need help with this new Firebase in Android, here is a link to help you out: https://firebase.google.com/docs/android/setup
I'm implementing web application based on Spring MVC and organized around DDD concepts. Currently I try to implement ticket reservation functionality. The customer can see number of tickets available for the particular event. Then, he can enter number of tickets to be reserved and submit form. Request is received by controller which calls application service responsible for registration. Application service logic is as follows:
Validate incoming parameters:
1A. Check if event with the given ID exists
1B. Check if number of tickets available allows for reservation
If validation passed, proceed with registration; otherwise, report an error.
I have some doubts about the proper way for reporting validation errors - especially for point 1B. Situation when number of tickets does not allow for reservation is not something very unusual. Customer can see number of tickets that is not fully synchronized with current number of tickets in database (eventual consistency) - some other person could reserve some tickets in the meantime.
Initially I was thinking about reporting this problems by throwing some specific exceptions. However, I can think of couple of other problematic situations and having one exception for each on of them doesn't sound very well.
The other option I was considering was throwing one type of exception containing error code. However, I don't know how to handle this situation in Spring MVC properly.
What are the best practices for such problems? How do you deal with them in your MVC applications? Any advices greatly appreciated.
I think these are business constraint brokens that cannot be recovered.
My current solution is Exception hierachy.
public abstract class UncheckedApplicationException extends RuntimeException {
//omitted factory methods and constructors
public abstract String getStatusCode();
public abstract String getI18nCode();//ignore this if you don't need i18n
public abstract String[] getI18nArgs();//ignore this if you don't need i18n
}
Any custom exception extends this one. I think this could avoid code like this:
try {
//invoke your application service
} catch (InsufficientInventoryException e) {
statusCode = INSUFFICIENT_INVENTORY;
} catch (ExpriedPriceException e) {
statusCode = EXPIRED_PRICE;
} catch (NoSuchProductException e) {
statusCode = NO_SUCH_PRODUCT;
} catch (Exception e) {
statusCode = UNKNOWN;
}
Controller code snippet:
try {
//invoke your application service here
statusCode = SUCCESS;
message = messageSource.getSuccess(locale));
} catch (UncheckedApplicationException e) {
statusCode = e.getStatusCode();
message = messageSource.getMessage(e, locale));
} catch (Exception e) {
statusCode = UNKNOWN;
message = messageSource.getUnknownError(e, locale));
}
//add statusCode & message to modelAttribute
You can use #ExceptionHandler to reduce boilerplate try-catch code if your Controller is well organized(but pretty difficult).
The other reason to use Excepton is that application service is often used to delimit transaction boundary. An exception has to be thrown if you want to rollback.
I am inheriting from System.Web.Http.AuthorizeAttribute to create a custom authorization/authentication routine to meet some unusual requirements for a web application developed using ASP.NET MVC 4. This adds security to the Web API used for Ajax calls from the web client. The requirements are:
The user must logon each time they perform a transaction to verify
someone else has not walked up to the workstation after someone has
logged on and walked away.
Roles cannot be assigned to the web service methods at program time.
They must be assigned at run time so that an administrator can
configure this. This information is stored in the system database.
The web client is a single page application (SPA) so the typical forms authentication does not work so well, but I am trying reuse as much of the ASP.NET security framework as I can to meet the requirements. The customized AuthorizeAttribute works great for requirement 2 on determining what roles are associated with a web service method. I accept three parameters, application name, resource name and operation to determine which roles are associated with a method.
public class DoThisController : ApiController
{
[Authorize(Application = "MyApp", Resource = "DoThis", Operation = "read")]
public string GetData()
{
return "We did this.";
}
}
I override the OnAuthorization method to get the roles and authenticate the user. Since the user has to be authenticated for each transaction I reduce the back and forth chatter by performing authentication and authorization in the same step. I get the users credentials from the web client by using basic authentication which passes the encrypted credentials in the HTTP header. So my OnAuthorization method looks like this:
public override void OnAuthorization(HttpActionContext actionContext)
{
string username;
string password;
if (GetUserNameAndPassword(actionContext, out username, out password))
{
if (Membership.ValidateUser(username, password))
{
FormsAuthentication.SetAuthCookie(username, false);
base.Roles = GetResourceOperationRoles();
}
else
{
FormsAuthentication.SignOut();
base.Roles = "";
}
}
else
{
FormsAuthentication.SignOut();
base.Roles = "";
}
base.OnAuthorization(actionContext);
}
GetUserNameAndPassword retrieves the credentials from the HTTP header. I then use the Membership.ValidateUser to validate the credentials. I have a custom membership provider and role provider plugged in to hit a custom database. If the user is authenticated I then retrieve the roles for the resource and operation. From there I use the base OnAuthorization to complete the authorization process. Here is where it breaks down.
If the user is authenticated I use the standard forms authentication methods to log the user in (FormsAuthentication.SetAuthCookie) and if they fail I log them out (FormsAuthentication.SignOut). But the problem seems to be that base OnAuthorization class does not have access to Principal that is updated so that IsAuthenticated is set to the correct value. It is always one step behind. And my guess is that it is using some cached value that does not get updated until there is a round trip to the web client.
So all of this leads up to my specific question which is, is there another way to set IsAuthenticated to the correct value for the current Principal without using cookies? It seems to me that cookies do not really apply in this specific scenario where I have to authenticate every time. The reason I know IsAuthenticated is not set to the correct value is I also override the HandleUnauthorizedRequest method to this:
protected override void HandleUnauthorizedRequest(HttpActionContext filterContext)
{
if (((System.Web.HttpContext.Current.User).Identity).IsAuthenticated)
{
filterContext.Response = new HttpResponseMessage(System.Net.HttpStatusCode.Forbidden);
}
else
{
base.HandleUnauthorizedRequest(filterContext);
}
}
This allows me to return a status code of Forbidden to the web client if the failure was because of authorization instead of authentication and it can respond accordingly.
So what is the proper way to set IsAuthenticated for the current Principle in this scenario?
The best solution for my scenario appears to be bypass the base OnAuthorization completely. Since I have to authenticate each time cookies and caching the principle are not of much use. So here is the solution I came up with:
public override void OnAuthorization(HttpActionContext actionContext)
{
string username;
string password;
if (GetUserNameAndPassword(actionContext, out username, out password))
{
if (Membership.ValidateUser(username, password))
{
if (!isUserAuthorized(username))
actionContext.Response =
new HttpResponseMessage(System.Net.HttpStatusCode.Forbidden);
}
else
{
actionContext.Response =
new HttpResponseMessage(System.Net.HttpStatusCode.Unauthorized);
}
}
else
{
actionContext.Response =
new HttpResponseMessage(System.Net.HttpStatusCode.BadRequest);
}
}
I developed my own method for validating the roles called isUserAuthorized and I am not using the base OnAuthorization any more since it checks the current Principle to see if it isAuthenticated. IsAuthenticated only allows gets so I am not sure how else to set it, and I do not seem to need the current Principle. Tested this out and it works fine.
Still interested if anyone has a better solution or can see any issues with this this one.
To add to the already accepted answer: Checking current sourcecode (aspnetwebstack.codeplex.com) for System.Web.Http.AuthorizeAttribute, it looks like the documentation is out of date. Base OnAuthorization() just calls/checks private static SkipAuthorization() (which just checks if AllowAnonymousAttribute is used in context to bypass the rest of the authentication check). Then, if not skipped, OnAuthorization() calls public IsAuthorized() and if that call fails, it then calls protected virtual HandleUnauthorizedRequest(). And that's all it does...
public override void OnAuthorization(HttpActionContext actionContext)
{
if (actionContext == null)
{
throw Error.ArgumentNull("actionContext");
}
if (SkipAuthorization(actionContext))
{
return;
}
if (!IsAuthorized(actionContext))
{
HandleUnauthorizedRequest(actionContext);
}
}
Looking inside IsAuthorized(), that's where Principle is checked against roles and users. So, overriding IsAuthorized() with what you have above instead of OnAuthorization() would be the way to go. Then again, you'd still have to probably override either OnAuthorization() or HandleUnauthorizedRequest() anyway to decide when to return a 401 vs a 403 response.
To add to the absolutely correct answer by Kevin, I'd like to say that I may slightly modify it to leverage the existing .NET framework path for the response object to ensure downstream code in the framework (or other consumers) is not adversely affected by some weird idiosyncrasy that can't be predicted.
Specifically this means using this code:
actionContext.Response = actionContext.ControllerContext.Request.CreateErrorResponse(HttpStatusCode.Unauthorized, REQUEST_NOT_AUTHORIZED);
rather than:
actionContext.Response = new HttpResponseMessage(System.Net.HttpStatusCode.Unauthorized);
Where REQUEST_NOT_AUTHORIZED is:
private const string REQUEST_NOT_AUTHORIZED = "Authorization has been denied for this request.";
I pulled that string from the SRResources.RequestNotAuthorized definition in the .NET framework.
Great answer Kevin! I implemented mine the very same way because executing OnAuthorization in the base class made no sense because I was verifying an HTTP Header that was custom to our application and didn't actually want to check the Principal at all because there wasn't one.
Asmx web service is called using Visual Studio generated code from MVC2 controller using code below.
Method call throws exception since web service certificate has expired. How to fix this so that web service can still used?
Using .NET 3.5 and MVC2.
public class AsmxController : Controller
{
public ActionResult Index()
{
var cl = new store2.CommerceSoapClient();
// System.ServiceModel.Security.SecurityNegotiationException was unhandled by user code
//Message=Could not establish trust relationship for the SSL/TLS secure channel with authority 'asmxwebservice.com'.
var vl = cl.GetVendorList( AsmxService.LicenseHeader() ,
new AsmxService.GetVendorListRequest());
return View();
}
}
}
From James blog:
So, for testing, we needed to find a way to bypass the certificate
validation. It turns out that you need to provide a
RemoteCertificateValidationCallback delegate and attach it to
ServicePointManager.ServerCertificateValidationCallback. What’s not
clear is what happens if two threads are competing to set this
property to different values, since it’s a static property. Reflector
suggests that the property set method doesn’t do anything fancy, so
you could easily get into a race condition.
so, he does the following:
// allows for validation of SSL conversations
ServicePointManager.ServerCertificateValidationCallback += new RemoteCertificateValidationCallback(ValidateRemoteCertificate);
// callback used to validate the certificate in an SSL conversation
private static bool ValidateRemoteCertificate(
object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors policyErrors)
{
if (Convert.ToBoolean(ConfigurationManager.AppSettings["IgnoreSslErrors"]))
{
// allow any old dodgy certificate...
return true;
}
else
{
return policyErrors == SslPolicyErrors.None;
}
}