Problems redirecting to access token entry point Oauth Token - spring

I am having problems with redirecting to access token entry point /oauth/token which will detail bellow. I am hoping someone could give me some light to it as I took a lot of time
implementing this.
Also, interesting is the fact that I cannot test with with SoapUI 5.0 community edition even following their instructions. It gest the authorization code but fails later as you need to set the redirect URI as "urn:ietf:wg:oauth:2.0:oob".
Since Spring-Security-Oauth2 lacks a lot of good documentation and I had spent lots of time debugging and documenting the work I decided to share
my comments and configuration code here which might also be helpfull to someone else.
I am using the following dependencies versions on my pom:
<org.springframework-version>4.0.5.RELEASE</org.springframework-version>
<org.springframework.security-version>3.2.5.RELEASE</org.springframework.security-version>
<org.springframework.security.oauth2-version>2.0.3.RELEASE</org.springframework.security.oauth2-version>
Now, the idea was to implement all the clientId objects, UserPrincipal, access, nonce and token stores using Cassandra as a persistency store. All those components
are working perfectly and are tested. In fact, it fetches all the authentication/authorization, creates authorization codes.
I've seen a bug recently on testing JDBC stores on Spring Oauth2 github but that was related to testing not the actuall implementation, specially because not
using JDBC.
I have wrote a client webapplication to access a REST resource which resides with the OAuth2 servers and Spring Security for logging in. All goes well until I go request
an access token to /oauth/token.
When I hit the secure Rest service first it properly starting doing redirections and goes tru DefaultOAuth2RequestFactory createAuthorizationRequest() method. Loads
the ClientDetails object perfectly with the secret etc from the store. So it has all the scopes, grants etc for the Oauth2 client. It also validates properly the redirectURIParameter
and resolves the redirect. Then it goes to the TokenStoreUserApprovalHandler and create the OAuth2Request object. Then, of course, tries to find an existing access token which
does not exist yet on the workflow. It creates the authenticationkey from authenticationKeyGenerator and queries the store which properly returns null at this point.
Then it redirects back to /oauth/authorize twice when on the second time it has an authorization code and marks as approved (AuthorizationEndPoint) inside approveOrDeny() method.
The authorizationCodeServices creates the code and stores it properly in my Cassandra store.
At this point it calls (AuthorizationEndPoint) getSuccessfulRedirect() where it adds the state parameter to the template.
Then it calls (OAuth2RestTemplate class) getAccessToken() method. Since the access token is fine and valid it then calls acquireAccessToken() which returns an accessTokenRequest with
{code=[Q19Y6u], state=[1PyzHf]} . Then it calls the accessTokenProvider to obtain an access token at obtainAccessToken(). Then the calls OAuth2AccessTokenSupport is called at
retrieveToken() method. And fails at getRestTemplate. The AuthorizationCodeResourceDetails is created perfectly with grant type authorization_code and it has both authorizationScheme
and clientAuthenticationScheme as header. The clientId is correct as the clientSecret. The id of the AuthorizationCodeResourceDetails is oAuth2ClientBean and the userAuthorizationURI is
http://myhost.com:8080/MyAPI/oauth/authorize. Headers show as
{Authorization=[Basic .....]}
The extractor is org.springframework.security.oauth2.client.token.OAuth2AccessTokenSupport.
The form is {grant_type=[authorization_code], code=[Xc7yni], redirect_uri=[http://myhost.com:8080/OAuthClient/support]}
And then the application freezes and it shows on the logs:
DEBUG: org.springframework.security.authentication.DefaultAuthenticationEventPublisher - No event was found for the exception org.springframework.security.authentication.InternalAuthenticationServiceException
DEBUG: org.springframework.security.web.authentication.www.BasicAuthenticationFilter - Authentication request for failed: org.springframework.security.authentication.InternalAuthenticationServiceException
Then I have the following Exception on my client web application:
org.springframework.web.util.NestedServletException: Request processing failed; nested exception is error="access_denied", error_description="Error requesting access token."
org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:973)
org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:852)
javax.servlet.http.HttpServlet.service(HttpServlet.java:618)
org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:837)
Now, I believe I have a few things wrong on my xml configuration for OAuth2 and Spring Security. So the configuration file follows.
I do have a few questions concerning it so here are the questions first:
1) <oauth2:authorization-server> I am not sure if I had this configured correctly. Please look at the comments I have on my xml file.
I have added the authorization-request-manager-ref parameter which points to my userAuthenticationManager bean, a authentication manager
which takes a authentication-provider user-service-ref="userService"
<oauth2:authorization-server client-details-service-ref="webServiceClientService"
token-services-ref="tokenServices" user-approval-page="/oauth/userapproval"
error-page="/oauth/error" authorization-endpoint-url="/oauth/authorize"
token-endpoint-url="/oauth/token" user-approval-handler-ref="userApprovalHandler"
redirect-resolver-ref="resolver">
<oauth2:authorization-code
authorization-code-services-ref="codes" />
<oauth2:implicit/>
<oauth2:refresh-token/>
<oauth2:client-credentials/>
<oauth2:password authentication-manager-ref="userAuthenticationManager"/>
<!-- <oauth2:custom-grant token-granter-ref=""/> -->
</oauth2:authorization-server>
2) authentication-manager oauthClientAuthenticationManager is used when "/oauth/token" is intercepted.
This is defined as follows:
<sec:authentication-manager id="oauthClientAuthenticationManager">
<sec:authentication-provider user-service-ref="clientDetailsUserService">
<sec:password-encoder ref="passwordEncoder" />
</sec:authentication-provider>
</sec:authentication-manager>
3) I have the following methodSecurityExpressionHandler bean defined which is used at sec:global-method-security.
Not sure if this is correct or not as well.
<beans:bean id="methodSecurityExpressionHandler"
class="org.springframework.security.oauth2.provider.expression.OAuth2MethodSecurityExpressionHandler" />
4) I also have a bean "clientCredentialsTokenEndpointFilter" which I believe is not recommended.
I use this as a custom-filter for entry point "/oauth/token" but I believe this is wrong.
<beans:bean id="clientCredentialsTokenEndpointFilter" class="org.springframework.security.oauth2.provider.client.ClientCredentialsTokenEndpointFilter">
<beans:property name="authenticationManager" ref="oauthClientAuthenticationManager"/>
</beans:bean>
A filter and authentication endpoint for the OAuth2 Token Endpoint. Allows clients to authenticate using request
parameters if included as a security filter, as permitted by the specification (but not recommended). It is
recommended by the specification that you permit HTTP basic authentication for clients, and not use this filter at
all.
5) Now for the Oauth Token Endpoint:
This is the endpoint /oauth/token as I have many questions here:
This is never reached.
Shall I have a custom-filter like clientCredentialsTokenEndpointFilter to it or not?
Do I have to have a http-basic entry point?
Shall I have an access attribute as in IS_AUTHENTICATED_FULLY or can I use an authority I have defined on my UserPrincipal object such as OAUTH_CLIENT I have added there?
What about the session? Shall I say "stateless" or
"never"
Shall I add the corsFilter to it as well?
Is the entry point correct? Which is the OAuth2AuthenticationEntryPoint class?
Do I have to add the csrf token? I believe not as it will
restrict it more.
Is the expression-handler correct as a org.springframework.security.oauth2.provider.expression.OAuth2WebSecurityExpressionHandle?
The authentication-manager-ref I can change from oauthClientAuthenticationManager to userAuthenticationManager.
<sec:http use-expressions="true" create-session="stateless"
authentication-manager-ref="userAuthenticationManager"
entry-point-ref="oauthAuthenticationEntryPoint" pattern="/oauth/token">
<sec:intercept-url pattern="/oauth/token" access="hasAuthority('OAUTH_CLIENT')" />
<!-- <sec:intercept-url pattern="/oauth/token" access="IS_AUTHENTICATED_FULLY" /> -->
<sec:http-basic entry-point-ref="oauthAuthenticationEntryPoint"/>
<!-- <sec:http-basic/> -->
<sec:anonymous enabled="false" />
<sec:custom-filter ref="clientCredentialsTokenEndpointFilter" after="BASIC_AUTH_FILTER" />
<sec:access-denied-handler ref="oauthAccessDeniedHandler" />
<sec:expression-handler ref="webSecurityExpressionHandler" />
<!-- <sec:custom-filter ref="corsFilter" after="LAST"/> -->
</sec:http>
I would like to add the full config file here but there is a limit.

The /oauth/token endpoint should be secured with client credentials, and it looks like you wired it to a user authentication manager. You didn't show the configuration or implementation of that, but judging by the InternalAuthenticationServiceException it is failing with an exception that isn't classified as a security exception. Fix those two things and you might be in business.
(The #Configuration style is much more convenient by the way, and I would recommend getting started with that and more of the defaults it provides, until you get the hang of it.)

Related

httpsession lifecycle events not working after using my custom UserDetailsService

I've created my own UserDetailsService and UserDetails implementations and hooked it up. I can create users, and login as users. However, if I login, logout, and then login again, I'm getting a redirect to a timeout error page. This is because I'm preventing concurrent logins, but it's not working - it used to with the "hello world" auth examples, but now with my own implementations that piece has stopped working correctly for some reason. Spring basically thinks there are 2 sessions when I login, logout, and login again.
Now - I thought this was all handled automatically ....perhaps using your own UserDetailsService means you actually have to implement session management somewhere else as well? I'm sort of blown away that's not mentioned in the docs or in the book Spring Security 3.1 so I'm assuming I'm missing something.
This is in my web.xml bit for listening to session life cycle events
<!-- This listener updates spring-security on httpsession lifecycle events,
in this case to ensure each user can have only 1 session at a time. -->
<listener>
<listener-class>org.springframework.security.web.session.HttpSessionEventPublisher</listener-class>
</listener>
and this is in my security.xml to prevent concurrent logins
<!-- This prevents the user from logging in more than once simultaneously -->
<security:session-management
invalid-session-url="/timeout.htm">
<security:concurrency-control
max-sessions="1" error-if-maximum-exceeded="true" />
</security:session-management>
My logout in the security context file is
<security:logout logout-url="/logout"
invalidate-session="true" delete-cookies="JSESSIONID,SPRING_SECURITY_REMEMBER_ME_COOKIE"
logout-success-url="/login.htm?logout" />
I've tried a few permutations of that. None seem to work. invalidate-session="true" is the default value, so I shouldn't even have to specify this. But it doesn't seem to be happening.
O.k., I just reverted everything to try and do in-memory auth and I'm getting the same errors. Meaning, I'm not using my custom implementations anymore. Sorry - I clearly have something wrong somewhere...and this is proving extremely difficult to find. I might have to start from scratch.
Do I have to do something special on logout with my custom UserDetailsService?
Any feedback or guidance is much appreciated.
To my understanding the error-if-maximum-exceeded attribute should be false. Settings the value to false will cause the original session to expire instead of throwing a exception as explained in http://docs.spring.io/spring-security/site/docs/3.0.x/reference/appendix-namespace.html#d0e7768
I discovered it was a conflict between using <session-management> in my configuration and my servlet container. I'm using STS 3.5 (custom Eclipse for Spring projects) with vFabric server that runs in the IDE. The Reference documentation did not refer to this in the actual Session Management section (Section 8). However, buried in Section 4 on auth is this little gem:
Note that if you use this mechanism to detect session timeouts, it may falsely report an error if the user logs out and then logs back in without closing the browser. This is because the session cookie is not cleared when you invalidate the session and will be resubmitted even if the user has logged out. You may be able to explicitly delete the JSESSIONID cookie on logging out, for example by using the following syntax in the logout handler:
<http>
<logout delete-cookies="JSESSIONID" />
</http>
Unfortunately this can’t be guaranteed to work with every servlet container, so you will need to test it in your environment
Well, apparently it doesn't work in STS 3.5
At first I tried to eliminate sections of my <session-management> tag so I could just control concurrency (i.e. have the user only able to log in with one session at a time). However, I just kept getting errors.
So, at this point I've removed the session management stuff altogether and will come back to it when ready to deploy.

How to Check whether a valid session is still existing at IDP?

I've implemented SSO using Spring Security SAML. Here is what currently working for me:
When I try to access any resource at SP, I'm redirected to my IdP(idp.ssocircle.com in my case) if I'm not logged in already. After successful authentication at IDP, I'm redirected back to SP and authorize the incoming SAML response and create a session for the respective user. Everything is cool till here!
But when I log out from my IDP(by clicking logout from idp.ssocircle.com externally), I shouldn't be able to access my SP which is not happening in my case.
Now what I'm thinking to do is may be write a new filter which checks for a valid session at IDP before processing any request on SP. I've searched a lot but couldn't find any solution to my problem.
Please give inputs on how can I implement this filter or is there any other way of doing this? Any suggestions are appreciated.
Does your IDP support and correctly initialize Single Logout? If so it could be related to this issue, just update to latest Spring SAML version or change property invalidateHttpSession in your logout handler to true:
<bean id="logoutSessionHandler"
class="org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler">
<property name="invalidateHttpSession" value="true"/>
</bean>

Spring Security | Method level security with #Secured/#PreAuthorize

I've been trying out 'Method Level' security on this application I've been working on. The idea is to secure a method which gets called from the presentation layer using DWR.
Now, I've tried adding the following annotations on my method:
#PreAuthorize("isAuthenticated() and hasRole('ROLE_CUSTOMER')")
And corresponding entry in my security context:
<global-method-security pre-post-annotations="enabled" />
On similar lines, I've tried #Secured annotation:
#Secured({"ROLE_CUSTOMER" })
And corresponding entry in my security context:
<global-method-security secured-annotations="enabled" />
Ideally, I would expect that if a user is not authenticated, they should be redirected to a 'Sign in' page and the 'ROLES' should not be checked. In this case, even for an unauthenticated user, this method call results in 'AccessDeniedException'. I need it to redirect the user to a login page in such a scenario.
To take it forward, I even tried handling the accessdenied exception by creating a custom AccessDenied Handler. Unfortunately, the handler never got called but the exception was thrown.
Here's the configuration:
<access-denied-handler ref="customAccessDeniedHandler"/>
This has a corresponding handler bean defined in the same file.
Still no luck. The accessdeniedhandler never gets called.
Just to summarize the requirement, I need to secure a method. If this method gets called, and the user is unauthenticated the user should get redirected to 'Sign In' page (which as of now is throwing Accessdenied execption).
Appreciate your help folks..
EDIT 1: Here is a snippet from the security context:
<http>
<intercept-url pattern="/*sign-in.do*" requires-channel="$secure.channel}" />
.....
.....
.....
<intercept-url pattern="/j_acegi_security_check.do" requires-channel="${secure.channel}" />
<intercept-url pattern="/*.do" requires-channel="http" />
<intercept-url pattern="/*.do\?*" requires-channel="http" />
<form-login login-page="/sign-in.do" authentication-failure-url="/sign-in.do?login_failed=1"
authentication-success-handler-ref="authenticationSuccessHandler" login-processing-url="/j_acegi_security_check.do"/>
<logout logout-url="/sign-out.do" logout-success-url="/index.do" />
<session-management session-authentication-strategy-ref="sessionAuthenticationStrategy" />
<access-denied-handler ref="customAccessDeniedHandler"/>
</http>
<beans:bean id="customAccessDeniedHandler" class="com.mypackage.interceptor.AccessDeniedHandlerApp"/>
I'm not very familiar with DWR, but I know that it's an RPC mechanism. The problem is that an RPC request sent by the client side javascript is not a regular page request initiated by the user who navigates the browser. The response to such an RPC request cannot possibly make the browser navigate away from the current page, because the response is processed by your javascript code and not by the browser.
What you can do is:
Implement a sort of eager authentication: redirect the user to a simple .jsp login page before allowing it to access the webapp (URL) that makes DWR (or any kind of RPC) requests.
If the AccessDeniedException thrown by the remote procedure gets propagated to the client side in some form, you can try to handle it from javascript code, for example by popping up a login dialog, and submitting user's credentials in an AJAX request. (In this case make sure to save the returned session id, and send it back with each subsequent requests.)
I would be interested in seeing the rest of your security.xml file (specifically, the <http> element), because if every user is being denied, it suggests to me that you have an <intercept-url> property which overrides calls to your controller class(es). If not, the added information might help shed some light on the problem.
Assuming I'm way off so far, another likely error point might be the specified access-denied-page itself -- if its path is a protected path (i.e. by <intercept-url>), or if it isn't specified, you might see the errors of which you speak.
Of course, I, too, am unfamiliar with DWR, so I'm somewhat obviously assuming a standard Spring MVC framework...
Okay, I have not had much success finding why I got an AccessDeniedException. Regardless, I've worked my way out of it till the time I find the reason. Here's a couple of approaches I took:
1) As mentioned by Zagyi, I was able to propagate the AccessDenied Exception over to the client side. I could create an exception handler to and redirect the user to the sign in page.
However, I took a different approach (which may not be the most optimal but seems to work as of now. Here's what I've done:
1) Created a DWRAjaxFilter and mapped to only the Remote Objects I am interested in. This would bean only the DWR calls to these remote methods get intercepted by the filter. This is because I do not want all DWR exposed methods to as for a sign in.
<create creator="spring" javascript="downloadLinksAjaxService">
<param name="beanName" value="downloadLinksAjaxService" />
<include method="methodOne" />
<include method="methodTwo" />
<filter class="com.xyz.abc.interceptor.DwrAjaxFilter"></filter>
</create>
2) Here is the actual filter implementation:
public class DwrSessionFilter implements AjaxFilter {
public Object doFilter(final Object obj, final Method method,
final Object[] params, final AjaxFilterChain chain)
throws Exception {
SecurityContext context = SecurityContextHolder.getContext();
Authentication auth = context.getAuthentication();
if (!auth.isAuthenticated()
|| auth.getAuthorities().contains(
new GrantedAuthorityImpl("ROLE_ANONYMOUS"))) {
throw new LoginRequiredException("Login Required");
} else {
return chain.doFilter(obj, method, params);
}
}
}
3) Here is the client side handler:
function errorHandler(message, exception){
if(exception && exception.javaClassName == "org.directwebremoting.extend.LoginRequiredException") {
document.location.reload();
}
}
4) I also added and exception mapper for DWR so that I could convert JAVA exceptions to JS exceptions:
<convert match="java.lang.Exception" converter="exception">
<param name='include' value='message'/>
</convert>
5) This seems to work well as of now. I'm still testing this to see if this fails somewhere.
Would appreciate any more inputs.

Spring security with multiple custom filters and roles

I am using Spring security with two filters:
- One filter for x.509 authentication for client certificates. All his filter does is extracts the username from certificate into principle.
- One filter to do header based authentication. The header should have username and roles. In this filter I check to make sure that there is a principal already present in the security context. If present I make sure that it matches whats in the headers. Then I extract the roles from the header and set the granted authorities.
I have a url pattern that I want to be made accessible to roles - 'ROLE_USER'
Now here is the problem. The request only hits the first filter(X.509), the role is missing in this header obviously and access is denied by spring security.
I cannot switch the order of the filters because if I do then X.509 filter provided by spring simply sees that principal is already present and does nothing making it useless.
Is there any way for the role check to be deferred until all filters are processed? Or any other way to achieve what I am trying to do.
Here is my spring security config:
<security:http auto-config="true" entry-point-ref="customEntryPoint">
<security:intercept-url pattern="/user/**" access="ROLE_USER"/>
<security:custom-filter after="EXCEPTION_TRANSLATION_FILTER" ref="x509Filter" />
<security:custom-filter after="FILTER_SECURITY_INTERCEPTOR" ref="headerFilter"/>
</security:http>
where the x509Filter is standard spring security filter configured as:
<beans:bean id="x509PrincipalExtractor" class="org.springframework.security.web.authentication.preauth.x509.SubjectDnX509PrincipalExtractor">
<beans:property name="subjectDnRegex" value="CN=(.*?),"/>
</beans:bean>
I can provide scrubbed up customHeaderFilter if needed but at this point the control never reaches the filter so it is inconsequential as to what happens in it.
Any help/guidance would be greatly appreciated.
Thanks to the pointer from #Maksym, the problem was resolved by changing 'after' to 'before' in the customHeaderFilter as follows:
<security:custom-filter before="FILTER_SECURITY_INTERCEPTOR" ref="headerFilter"/>
FilterSecurityInterceptor is responsible for handling security of HTTP resources, including applying role checks. In my case X509Filter would fire setting principal but would not set any authorities. This would cause the interceptor to deny access to the resource and the headerFilter would not even come into the picture.
By setting the position of the headerFilter to before the interceptor allowed the principal and authentication object in the security context to be set up correctly with the given authorities, leading to the expected behavior.

Spring Security 3.1 redirect after logout

I was reading many tutorials and none of them is working for me...
I use Spring 3.1.x with Spring Security. I have a bunch of secured url and many unsecured. Now, when the user is logged in and tries to logout I want him to stay in the same page as he was before so I use this:
<beans:bean id="logoutSuccessHandler" class="org.springframework.security.web.authentication.logout.SimpleUrlLogoutSuccessHandler">
<beans:property name="useReferer" value="true"/>
</beans:bean>
This works fine, however when the user logs out from the secured page it redirects him to the login page, and I would like to redirect to home page.. How can I achieve this?
Thanks in advance!
Since you have custom logic for redirecting, you need a custom LogoutSuccessHandler.
In this handler, you need to add this logic:
String refererUrl = request.getHeader("Referer");
String normalizedRefererUrl = ...; // "Normalize" (if needed) the URL so it is in the form that you need.
if (requiresAuthentication(normalizedRefererUrl, authentication)) {
response.sendRedirect(request.getContextPath()); // home page
} else {
response.sendRedirect(refererUrl); // or normalizedUrl
}
In your requiresAuthentication() method, you need to use some part of Spring Security that determined if the URL needs authentication.
You can use a WebInvocationPrivilegeEvaluator reference there. You get a hold of it through Spring through autowiring by class (since there will be a bean implementing WebInvocationPrivilegeEvaluator).
The evaluator has a method that you can use, isAllowed(uri, authentication).
<security:http auto-config="true">
<security:form-login login-page="/spring/login"
login-processing-url="/spring/loginProcess"
default-target-url="/spring/main"
authentication-failure-url="/spring/login?login_error=1" />
<security:logout logout-url="/spring/logout" logout-success-url="/spring/logout-success" />
</security:http>
logout-success-url from the docs or for a custom succeshandler
as per documentation for spring security if you don't specify logout-success-url then it should be redirecting /. check this configuration and may be you can use SimpleRedirectInvalidSessionStrategy

Resources