Spring security, x509 and switching user - spring

Here's the scenario. I have a WAR that is connected to using SSL from an Eclipse RCP client using an X.509 certificate. After I verified that I have the certificate I want to retrieve the user details (ie. implement the loadUserByUsername) and read the userId from the request header (supplied by the client) and NOT use the supplied DN from the certificate. Is this possible? Essentially I trust the caller to supply me with the userId that I should use in my Spring security context.
My Spring configuration currently looks like this and works for the standard case of extracting the DN from the X.509 cert and loading the user.
<security:http>
<security:intercept-url pattern="/**" requires-channel="https" />
<security:x509 subject-principal-regex="^(.*?)$" />
</security:http>
<security:authentication-manager>
<security:authentication-provider user-service-ref="myUserDetailsService" />
</security:authentication-manager>
I need this to support the scenario of PKI client (user1) -> PKI service A -> PKI service B (run service B as user1).*

Related

Spring OAuth2 token without ClientId and ClientSecret for External Clients

We have OAuth token generation using Spring which accepts Username/Password/ClientId/Secret, which works perfect. For External Client we just need input as username and password and generate OAuth Token.
<security:http pattern="/oauth/token" create-session="stateless"
authentication-manager-ref="clientAuthenticationManager"
xmlns="http://www.springframework.org/schema/security">
<security:intercept-url pattern="/oauth/token" access="IS_AUTHENTICATED_FULLY" />
<security:anonymous enabled="false" />
<security:http-basic entry-point-ref="clientAuthenticationEntryPoint" />
<!-- include this only if you need to authenticate clients via request parameters -->
<security:custom-filter ref="clientCredentialsTokenEndpointFilter" after="BASIC_AUTH_FILTER" />
<security:access-denied-handler ref="oauthAccessDeniedHandler" />
</security:http>
Below is the new code that we need to add, but it is asking for username and password in browser.
<security:http pattern="/**external**/oauth/token" create-session="stateless"
authentication-manager-ref="clientAuthenticationManager"
xmlns="http://www.springframework.org/schema/security">
<security:intercept-url pattern="/external/oauth/token" access="IS_AUTHENTICATED_FULLY" />
<security:anonymous enabled="false" />
<security:http-basic entry-point-ref="clientAuthenticationEntryPoint" />
<security:custom-filter ref="clientCredentialsTokenEndpointFilter" after="BASIC_AUTH_FILTER" />
<security:access-denied-handler ref="oauthAccessDeniedHandler" />
</security:http>
Please guide if we can generate OAuth without clientId and internally pass clientId to generate OAuth.
You can never generate an OAuth token without a clientId! Oauth2 has 3 ways of creating a token, Implicit, Code, and user/pass. The last should be avoided, since it means that the Oauth client will get access to the user's credentials, and OAuth was built to prevent exactly that. Implicit token are granted using only the user's credentials (typically involving only the browser). In Code-mode the OAuth client received a code (should not be in a browser), which is then exchanged to a Token. The code to Token exchange require that the Oauth client authenticates, using it's clientId and a secret, this is typically done using Basic Authentication.
I think what you need is Resource Owner Password grant type which is explained in https://www.rfc-editor.org/rfc/rfc6749#section-1.3.3
Resource Owner Password grant type should only be used with the trusted clients. So if the external client you are talking about is a trusted client (Like a native mobile app developed by the same company. ex. Facebook Mobile App), this can be used.
Flow is explained in https://www.rfc-editor.org/rfc/rfc6749#section-4.3.1
The most important aspect of Resource Owner grant type is client should not store user name and password.

Spring Security - Access Token without client_secret in parameters

I have a spring security oauth2 based application, configured with a JDBC Client Store. As per the OAuth2 specs, client secret must only be used when client-server connections are trustworthy, and certainly not from a web application - where the client secret could be extracted from.
So the question is - how do we configure to let the /oauth/token requests with a grant type as "password" produce an access token, without the client_secret key in the POST parameters?
This is my authorization server configuration. Pretty basic I would say.
<sec:http pattern="/token" create-session="stateless" use-expressions="true" authentication-manager-ref="authenticationManager">
<sec:headers>
<sec:frame-options policy="DENY" />
<sec:hsts />
</sec:headers>
<sec:csrf disabled="true" />
<sec:anonymous enabled="false" />
<sec:http-basic entry-point-ref="clientAuthenticationEntryPoint" />
<sec:custom-filter ref="clientCredentialsTokenEndpointFilter" before="BASIC_AUTH_FILTER" />
<sec:access-denied-handler ref="oauthAccessDeniedHandler" />
</sec:http>
According to RFC6749, the OAuth2 Specs, a password grant type must have the client secret passed in either as a request body parameter or as a BASE64 encoded string. The password grant type is not suited for applications that has lesser security or high risk of secrets being exposed to the outer world.
For applications which has a user-agent (web browsers), Implicit Grant Type is the best sought out method.
Refer the OAuth2 Specs here

Spring REST Basic Authentication Design Approach

Environment :
Spring 4
Spring Security 4
Spring MVC 4
Hibernate 4
MySQL
Issue :
Below is the requirement :
1)We are developing a Spring REST service for inventory management.
2)This web service will be consumed by .NET client. (or may be mobile device in future)
3)The users of REST service need to be authenticated. The user will use login form displayed by .NET client and if authentication is successfull , he will be
allowed to consume REST API.
4)If authentication fails , user won't be allowed entry into REST service.
Now we have decided to use Basic Authentication for this.
My question is : How do we achieve this using Spring MVC REST and Spring security ?
Below is my first attempt :
application-security.xml
<http auto-config="true" use-expressions="true">
<intercept-url pattern="/usermanagement/authenticate" access="permitAll"/>
<intercept-url pattern="/abhishek/*" access="hasRole('ROLE_ADMIN')"/>
<http-basic/>
<csrf disabled="true"/>
</http>
<authentication-manager>
<authentication-provider>
<user-service>
<user name="Atul" password="12345" authorities="ROLE_ADMIN" />
</user-service>
</authentication-provider>
</authentication-manager>
Following is the flow happening right now :
1)The /authentication API looks up user in Db and returns Http Status code 201(success ) or 401 (failure) accordingly. (this url is unsecured)
2)If success , client puts username/password as Authorization header (which is used in login) and sends this header for future Http requests.
3)Now once next request comes (this is secured), spring security comes into picture and again authentication happens here.
But this time it will be Spring provided.
4)So there are two authentication mechanism are being used .
5)I know I am messing up here , but not able to decide on what is the correct approach to design this.
6)How can client be provided the authentication capability by hooking into Spring security ? He needs to know authentication success/failure
immediately after he logs in.
Please help since I am struggling a lot on this.

Support SAML SSO and normal login

I have an application which is accessed by two types of users, internal and external.
I need to authenticate external users using SAML.
I need to authenticate internal users with the normal form-based login. My application need to support both types of users. I use spring security frame work.
Is it possible to support both types of users? if so can you suggest the approach at high level? Thanks.
You can easily enable support for both form and SAML authentication with configuration similar to this:
<http entry-point-ref="authenticationEntryPoint" authentication-manager-ref="authenticationManager">
<intercept-url pattern="/**" access="IS_AUTHENTICATED_FULLY"/>
<form-login login-page="/login" />
<custom-filter before="FIRST" ref="metadataGeneratorFilter"/>
<custom-filter after="BASIC_AUTH_FILTER" ref="samlFilter"/>
</http>
Make sure that your AuthenticationManager contains the samlAuthenticationProvider. And of course include other configuration parts from the Spring SAML sample application.
You can then create your custom login page which presents user with username+password fields for form-based authentication and a link/picture (or multiple of them) which initialize authentication with the IDP (by redirecting user to scheme://host:port/saml/login?idp=selectedIdpEntityId).
Your users then decide which one to use - depending on whether they's internal or external.
The part of Spring SAML documentation touching on this subject is in chapter Spring Security integration.

Spring Security 3 RestTemplate POST to j_spring_security_check

I am using Spring Security 3 with REST endpoints. I managed to get a basic Spring Security working.
Part of the security-context.xml
<security:http auto-config="true" use-expressions="true" access-denied-page="/rest/denied" >
<security:intercept-url pattern="/rest/*" access="ROLE_USER"/>
and basic config as found on the web
<security:authentication-manager>
<security:authentication-provider user-service-ref="userDetailsService">
<security:password-encoder ref="passwordEncoder"/>
</security:authentication-provider>
<!-- Use a Md5 encoder since the user's passwords are stored as Md5 in the database -->
<bean class="org.springframework.security.authentication.encoding.Md5PasswordEncoder" id="passwordEncoder"/>
<!-- An in-memory list of users. No need to access an external database layer.
See Spring Security 3.1 Reference 5.2.1 In-Memory Authentication -->
<!-- john's password is admin, while jane;s password is user -->
<security:user-service id="userDetailsService">
<security:user name="john" password="21232f297a57a5a743894a0e4a801fc3" authorities="ROLE_USER, ROLE_ADMIN" />
<security:user name="jane" password="ee11cbb19052e40b07aac0ca060c23ee" authorities="ROLE_USER" />
</security:user-service>
I want to login to j_spring_security_check using a RestTemplate POST.
HttpEntity<String> entity = new HttpEntity<String>(request, headers);
HashMap<String, String> map = new HashMap<String, String>();
map.put("j_username", "john");
map.put("j_password","21232f297a57a5a743894a0e4a801fc3");
String response = restTemplate.postForObject("http://localhost:8080/rest/j_spring_security_check", map, String.class);
but in the log, it seems the username parameter is not being read
DEBUG o.s.s.authentication.ProviderManager - Authentication attempt using org.springframework.security.authentication.dao.DaoAuthenticationProvider
DEBUG o.s.s.a.d.DaoAuthenticationProvider - User '' not found
DEBUG o.s.s.w.a.UsernamePasswordAuthenticationFilter - Authentication request failed: org.springframework.security.authentication.BadCredentialsException: Bad credentials
What is the correct way to get the REST Template to post auth credentials? Is there a better way to login in/ get authorized other than j_spring_security_check? Does the information go in the header?
Thanks in advance.
This seems like a duplicate of another SO question. You are probably approaching this the wrong way, though. Typically if you are issuing a REST request you wouldn't be authenticating at the same time - this doesn't make any sense - certainly not using form POST style logic.
For authentication of REST requests you should be using another form of authentication (assuming these requests are generated programmatically):
* HTTP Basic auth
* X.509 certificates
OR if this is happening through an XHR / Javascript origin, you should be prepared to have the request fail and redirect the user to the login mechanism. Typically handling REST style requests with Spring Security is not at all the same as handling regular secured pages. You should be prepared for some amount of complexity.
Good luck!

Resources