Spring Security privacy policy message after successful login - spring

I'm looking for a way to include a warning page after a successful login in my spring security app. The warning page will display a message to the user who has already successfully logged in that by pressing "Yes" they agree to the terms and conditions bla bla... I want to ensure that they can't access any resources unless they click "Yes".
How can I include this in my journey? I've already implemented a custom success handler if that would help.
Thank's in advance.

This will be a matter of choice to implement it.
You can do so by creating custom implementation of UserDetailsService. This interface has only one method namely loadUserByUsername, which returns instance of UserDetails which is again an interface from Spring Security. By implementing UserDetails interface to your User POJO/Entity you can have access to some useful messages which can check user is active or enabled or credentials are non expired, etc. Have a look at javadoc. From there you can handle this that the user has accepted terms and conditions or not.
Another way is to create custom SpEL to check whether user has accepted terms or not.

So the solution is actually somewhat simple. Unfortunately, took a couple of days trying to get to the simplest solution.
Essentially what I did was: In my custom UserDetailService class, I overrode the createUserDetails method and set the combinedAuthorities to be:
List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
authorities.add(new GrantedAuthorityImpl("ROLE_NEEDS_TO_ACCEPT_POLICY"));
combinedAuthorities = authorities;
So at the moment, this is their only role, i.e. they aren't authorised to access any of the other resources as mapped in my spring security xml.
In my custom success handler, I forwarded them onto /policy, which can bee seen by users with role ROLE_NEEDS_TO_ACCEPT_POLICY, which is mapped to a Controller which returns a jsp for them to accept/decline the terms and conditions etc...
If they clicked yes, their response is captured in the same controller's post method which then load's their actual roles and grants them.
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>(auth.getAuthorities());
authorities.add(new GrantedAuthorityImpl('FETCH_ACTUAL_FROM_ROLES_TABLE'));
Authentication newAuth = new UsernamePasswordToken(auth.getPrincipal(),auth.getCredentials(),authorities)
SecurityContextHolder.getContext().setAuthentication(newAuth);
And that's it... Hope this helps someone.

Related

Spring security - Is username and password must for creating authentication

I am using spring security to authenticate a user. The user is authenticated by a third party and will already be authenticated when he reaches my application.
To implemented this, I have simulated a Authentication object.
I don't have any username and password and instead just have identifier. I check if this identifier is valid or not using my custom code.
My query is as follows:
Do I require a username and password to create a authentication object.
I have done without providing username and password and my application works fine.
I just want to ensure that I am using spring-security correctly.
Is there any impact of not putting username and password in Authentication object. I read below in AbstractUserDetailsAuthenticationProvider:
// Ensure we return the original credentials the user supplied,
// so subsequent attempts are successful even with encoded passwords.
I have also implemented a custom provider.
What does above comments means?
Is my approach correct?
The Authentication interface in Spring Security represents a token for carrying out validations against the configured security rules and the current call context. This interface has six methods of interest - getPrincipal, getCredentials, getDetails, getAuthorities, isAuthenticated and setAuthenticated.
Since you are authenticating users on your own, you should be mostly concerned with calling setAuthenticated(true) at an appropriate stage in the flow so that isAuthenticated starts returning true to indicate an authenticated user. Additionally, you may add GrantedAuthoritys to the Authentication for any role-based checks to work correctly.
However, it will be useful to make sure that getPrincipal (username in the case of form login) returns a unique value per user or per session. This will prevent the possibility of user sessions getting interchanged due to non-unique principal, which is used by the framework to identify users uniquely.
You may leave getCredentials and getDetails unimplemented. In fact, getCredentials (password in the case of form login) should be left unimplemented in your case because your application does not have the credentials used to actually authenticate the user; plus, it is a security risk to keep the credentials around after the user has been authenticated successfully.

JSP/Tomcat secure login with sessionstorage

I have a system running on Tomcat, with HTML/JSP in front-end, and java/Spring/Struts in backend.
I made a login-feature where the user enters his username and password.
In backend, I validate the username and password to the stored user in DB.
If match, I store the username in HTTPsession:
session.setAttribute( "username", name );
Then, on every class-action in backend, I add the following code:
HttpSession session = request.getSession();
if(session.getAttribute("username") == null) {
return mapping.findForward("invalidUser");
}
the invalidUSer-mapping redirects the user back to the login-page.
How secure is this?
Is there a way to check the httpsession without adding my validation-code to every class?
Do you guys have tips (or examples/tutorials) on how to do this differently? The system is already created and in production, so I do not want to do too many architecural changes.
As you are already using Spring in your project, you may want to look into Spring Security to replace your bespoke security mechanisms. You can configure it to protect certain resources within your application, authenticate against bespoke database back-ends, LDAP directories, etc. This will allow you to remove all manual checking of the session to see if the user is authenticated, and will redirect anonymous users to the specified login page when they attempt to access protected resources.
Along with the spring security filter definition in web.xml, the configuration can be specified in a single spring-security.xml file (imported into your root app config) using the security:http namespace to define the login page, protected resources, logout page, security headers etc. You could use a org.springframework.security.core.userdetails.jdbc.JdbcDaoImpl instance configured as a bean to define the user service which can be referenced by the authentication-provider - see the docs, its very flexible.
Hope that's useful.

not able to understand spring social at all especially the ProviderSignInController

i am trying to understand what is ProviderSignInController does but i am facing a hard time understanding it.
So when i click login with facebook i go to facebook login page and than after entering my credentials the following method is called
org.springframework.social.connect.web.ProviderSignInController.oauth1Callback(String, NativeWebRequest)
/**
* Process the authentication callback from an OAuth 2 service provider.
* Called after the user authorizes the authentication, generally done once by having he or she click "Allow" in their web browser at the provider's site.
* Handles the provider sign-in callback by first determining if a local user account is associated with the connected provider account.
* If so, signs the local user in by delegating to {#link SignInAdapter#signIn(String, Connection, NativeWebRequest)}.
* If not, redirects the user to a signup page to create a new account with {#link ProviderSignInAttempt} context exposed in the HttpSession.
* #see ProviderSignInAttempt
* #see ProviderSignInUtils
*/
#RequestMapping(value="/{providerId}", method=RequestMethod.GET, params="code")
public RedirectView oauth2Callback(#PathVariable String providerId, #RequestParam("code") String code, NativeWebRequest request) {
try {
OAuth2ConnectionFactory<?> connectionFactory = (OAuth2ConnectionFactory<?>) connectionFactoryLocator.getConnectionFactory(providerId);
Connection<?> connection = connectSupport.completeConnection(connectionFactory, request);
return handleSignIn(connection, connectionFactory, request);
} catch (Exception e) {
logger.error("Exception while completing OAuth 2 connection: ", e);
return redirect(URIBuilder.fromUri(signInUrl).queryParam("error", "provider").build().toString());
}
}
what i am not understand is it says Handles the provider sign-in callback by first determining if a local user account is associated with the connected provider account.
and in the second line it says If so, signs the local user in by delegating to {#link SignInAdapter#signIn(String, Connection, NativeWebRequest)}
which i understood.
but i am not able to understand this line which says If not, redirects the user to a signup page to create a new account with {#link ProviderSignInAttempt} context exposed in the HttpSession.
I am thinking now that for the first time when i try to login with facebook...there will be no user in connection repository.... so every time i will get redirected to signup page. And spring social is meant that u dont have to do sign up and use facebook credentials.
So i cannot understand what is the logic behind all this.
Your understanding is not entirely accurate. The typical way that ProviderSignInController works is the way you described it. It works by first getting user authorization with Facebook (or whatever provider it's dealing with), then using that authorization to fetch the user's ID. Then it compares the user's ID with a previously established connection (probably made with ConnectController) and authenticating the user associated with that connection. In this scenario, there must be an existing user and that user must have previously established a connection with Facebook.
If no matching connection is found, then it offers up the application's registration/signup screen for the user to register with your application. (This assumes that the user is not already registered.) After registration, the application has the option of completing the connection...that is, creating a new connection for the newly registered user. It does this by calling postSignUp() on ProviderSignInUtils. Spring Social Showcase does this in SignupController: https://github.com/spring-projects/spring-social-samples/blob/master/spring-social-showcase/src/main/java/org/springframework/social/showcase/signup/SignupController.java.
There is another way, though, that does not require an existing connection, nor does it require that your application even maintain a user database. This approach is known as "implicit signup", meaning that by authorizing with Facebook, the user is implicitly registered with your application. To use implicit signup, you must inject an instance of SignInAdapter into JdbcUsersConnectionRepository. To see this in action, look at SocialConfig.java for the Spring Social Quickstart example: https://github.com/spring-projects/spring-social-samples/blob/master/spring-social-quickstart/src/main/java/org/springframework/social/quickstart/config/SocialConfig.java.
Note that implicit signup, as it's currently implemented, is a function of JdbcUsersConnectionRepository and not the more generic UsersConnectionRepository. That's unfortunate, because it means that the feature can only be used if you're using JdbcUsersConnectionRepository or if whatever implementation of UsersConnectionRepository you're using supports it. This has bugged me for awhile, so I've created https://jira.spring.io/browse/SOCIAL-439 to address this concern.

Two factor authentication with Spring Security like Gmail

Here, my scenario is bit similar to two-factor authentication of Gmail. When a user logs in successfully(SMS code is send to user) then he is challenged with another page to enter the SMS code. If user gets the SMS code correctly he is shown the secured page(like Gmail Inbox).
I did this bit of research on this and suggestion is to rather than giving ROLE_USER upon login, gave him PRE_AUTH_USER and show the second page where he enters the SMS code; upon success give them ROLE_USER.
However, my question is Spring has InsufficientAuthenticationException and in this scenario we won't make use of it. Will there be other better ways of implementing two factor authentication in my scenario?
P.S. I have bit of customized spring security configuration. In my Login page apart from username and password I have Recaptcha validation as well, also my authenticationProviderm authenticationSuccessHandler, logoutSuccessHandler, accessDeniedHandler all are customized.
Upon SMS code validation success, you could grant ROLE_USER authority as follows.
private void grantAuthority() {
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>(auth.getAuthorities());
authorities.add(new SimpleGrantedAuthority("ROLE_USER"));
Authentication newAuth =
new UsernamePasswordAuthenticationToken(auth.getPrincipal(), auth.getCredentials(),
authorities);
SecurityContextHolder.getContext().setAuthentication(newAuth);
}
The code is from copied from a blog post ,and sample application which has implemented two-factor authentication. If I had found it bit earlier it would save a lot of time !!!
Try to throw InsufficientAuthenticationException if the first level of authentication passes, then catch it with ExceptionTranslationFilter and forward to the second level of authentication page.
The two factor authentication page can resubmit the user name and password in hidden fields, together with the two factor token. In this second time the custom authentication provider would be able to authenticate successfully the user.

Spring Security Recommended Design To Request User Login to Different User With Different Role

I have the following use case and need recommendations on the proper implementation. To be clear can this be done through configuration or do I need to implement new code?
Business Use Case
The business wants to allow a user to login via social media sites and access some of their pages. But in order to access pages that deal with $$ the user must login via the applications local account.
Technical Use Case
Allow users to login via Facebook or other provider and provide role USER_PARTIAL_RIGHTS
If user accesses a page with role USER_FULL_RIGHTS prompt the user to login to an account that is a local JDBC stored account.
This authentication must also ensure that the page is protected by USER_FULL_RIGHTS role and not other roles.
I am using grail spring security plugin, but I am expecting to have to customize the plugin.
So what are recommendations for doing this? A couple of ideas that I have are:
Technical Ideas
custom spring access denied handler
custom access denied controller instead of the stock jsp page
From what i understand from your question, here is my suggestion.
For login via Facebook use Spring Social. Here is the documentation. The implementations are straightforward. Write a custom signin method and set the authorities for partial rights, something like this:
public void signin(String userId) {
authorities = new ArrayList<GrantedAuthority>();
//set your partial rights authority
SecurityContextHolder.getContext().setAuthentication(new UsernamePasswordAuthenticationToken(userId, null, authorities));
}
And do a method level security implementation using the #secured annotation to access the page that needs full rights. Something like this
#Secured("USER_FULL_RIGHTS ")
yourMethod(){
//code
}
This would prompt for a login where can use authentication from applications local account.
What we ended up implementing is a controller that looks at the role and redirects the user to the correct landing page. Kinda messy, but it works.
Collection<GrantedAuthority> inferred = SpringSecurityUtils.findInferredAuthorities(SpringSecurityUtils.getPrincipalAuthorities());
if(ifAnyGranted('ROLE_FOO', inferred)) {
redirect(controller: 'foo',action: 'home')
return
}

Resources