Spring Rest Authentication with a response - spring-security

I have setup a security context meant for REST. The configuration is as
<!-- authentication manager and password hashing -->
<authentication-manager alias="authenticationManager">
<authentication-provider ref="daoAuthenticationProvider" />
</authentication-manager>
<beans:bean id="daoAuthenticationProvider"
class="org.springframework.security.authentication.dao.DaoAuthenticationProvider">
<beans:property name="userDetailsService" ref="userDetailsService" />
<beans:property name="passwordEncoder" ref="passwordEncoder" />
</beans:bean>
<beans:bean id="userDetailsService" name="userAuthenticationProvider"
class="com.myapp.auth.AuthenticationUserDetailsGetter" />
<beans:bean id="passwordEncoder"
class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder">
</beans:bean>
<global-method-security pre-post-annotations="enabled" />
<!-- web services -->
<http use-expressions="true" pattern="/rest/**"
disable-url-rewriting="true" entry-point-ref="restAuthenticationEntryPoint">
<custom-filter ref="restProcessingFilter" position="FORM_LOGIN_FILTER" />
<intercept-url pattern="/rest/login" access="permitAll"/>
<intercept-url pattern="/rest/**" access="isAuthenticated()" />
<logout delete-cookies="JSESSIONID" />
</http>
<beans:bean id="restProcessingFilter" class="com.myapp.auth.RestUsernamePasswordAuthenticationFilter">
<beans:property name="authenticationManager" ref="authenticationManager" />
<beans:property name="filterProcessesUrl" value="/rest/login" />
</beans:bean>
And I overrided the UsernamePasswordAuthenticationFilter as
#Override
public Authentication attemptAuthentication(HttpServletRequest request,
HttpServletResponse response) {
Authentication authentication = null;
String username = request.getParameter("j_username");
String password = request.getParameter("j_password");
boolean valid = authService.authenticate(username, password);
if (valid) {
User user = updateLocalUserInfo(username);
authentication = new UsernamePasswordAuthenticationToken(user,
null, AuthorityUtils.createAuthorityList("USER"));
SecurityContextHolder.getContext().setAuthentication(authentication);
}
return authentication;
}
The above authentication is working fine when I tried it with
RestClient restClient = new RestClient();
String result = restClient.login("hq", "a1234567"); // RestTemplate.postForObject
The only thing left is the result from the authentication post (atm, result is null). How can I configure my security configuration in order to retrieve some result ? A flag or session ID will suffice.

I think best bet here would be AuthenticationSuccessHandler.
As this will only kick in if the authentication was successful.
You can generate some sort of UUID and set that in your response directly. I have used very similar approach for ReST Auth and have not hit any problems yet.
For detailed implementation guide please refer : https://stackoverflow.com/a/23930186/876142
Update for comment #1 :
You can get response just like any normal ReST request.
This is how I am sending back my Token as JSON
String tokenJsonResponse = new ObjectMapper().writeValueAsString(authResponse);
httpResponse.addHeader("Content-Type", "application/json");
httpResponse.getWriter().print(tokenJsonResponse);
Assuming you know how to use RestTemplate, rest is trivial.

Related

Unable to hit custom AuthenticationProvider using Spring security 5.1.1

I'm using Spring security 5.1.1. I'm trying to create two security entryPoints for my application: one for REST and another for the secured urls of the application. I've created CustomAuthenticationProvider by implementing AuthenticationProvider for the authenticationManager.
I'm following the examples in :
Spring Security for a REST API and
Spring Security – Two Security Realms in one Application
But on the login page, when I enter username and password it doesn't hit the CustomAuthenticationProvider.authenticate() method at all, rather it goes to logout.html.
Below is my xml snippet of http:
<!-- Configuration for API -->
<security:http entry-point-ref="restAuthEntryPoint" pattern="/api/**" use-expressions="true">
<intercept-url pattern="/api/**" access="hasAnyRole('ROLE_DRIVER','ROLE_PARENT') and isAuthenticated()"/>
<intercept-url pattern="/api/driver/**" access="hasRole('ROLE_DRIVER') and isAuthenticated()"/>
<intercept-url pattern="/api/parent/**" access="hasRole('ROLE_PARENT') and isAuthenticated()"/>
<form-login
authentication-success-handler-ref="apiSuccessHandler"
authentication-failure-handler-ref="apiFailureHandler" />
<custom-filter ref="apiAuthenticationFilter" after="BASIC_AUTH_FILTER" />
<logout />
</security:http>
<beans:bean id="apiAuthenticationFilter" class="org.springframework.security.web.authentication.www.BasicAuthenticationFilter">
<beans:constructor-arg name="authenticationEntryPoint" ref="restAuthEntryPoint"/>
<beans:constructor-arg name="authenticationManager" ref="authenticationManager"/>
</beans:bean>
<beans:bean id="restAuthEntryPoint"
class="com.main.sts.api.security.RestAuthenticationEntryPoint"/>
<beans:bean id="apiSuccessHandler"
class="com.main.sts.api.security.MySavedRequestAwareAuthenticationSuccessHandler"/>
<beans:bean id="apiFailureHandler" class=
"org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler"/>
<!-- Configuration for Rest-API finished-->
<security:http auto-config="true" use-expressions="true" authentication-manager-ref="authenticationManager">
<intercept-url pattern="/school_admin/*"
access="hasAnyRole('ROLE_SCHOOLADMIN','ROLE_GUEST','ROLE_SCHOOLTEACHER','ROLE_PARENT')" />
<form-login login-page="/login" authentication-failure-url="/loginfailed"/>
<!-- <custom-filter before="FORM_LOGIN_FILTER" ref="userAuthenticationProcessingFilter" /> -->
<logout invalidate-session="true" logout-success-url="/logout" />
<access-denied-handler error-page="/404" />
<session-management invalid-session-url="/logout.html">
</session-management>
<sec:headers >
<sec:cache-control />
<sec:hsts/>
</sec:headers>
</security:http>
<authentication-manager alias="authenticationManager">
<authentication-provider ref="customAuthenticationProvider" />
</authentication-manager>
<beans:bean id="customAuthenticationProvider" class="com.main.sts.util.CustomAuthenticationProvider">
<beans:property name="loginService" ref="loginService" />
</beans:bean>
Even if I commented out the configuration for the REST-api, still I don't get hit to that class.
Here's my CustomAuthenticationProvider:
#Component
public class CustomAuthenticationProvider implements AuthenticationProvider {
#Override
public Authentication authenticate(Authentication authentication) {
// **I never hit this class**
}
#Override
public boolean supports(Class<?> authentication) {
return authentication.equals(UsernamePasswordAuthenticationToken.class);
}
filter is defined correctly in web.xml:
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
springSecurityFilterChain /*
In the login jsp, I've setup form as below:
<form class="form-vertical login-form" name='f' action="<c:url value='j_spring_security_check' />" method="post">
I can't access secured urls, it takes me to the login page; this means - this filter works. But why can't I hit CustomAuthenticationProvider? Why does it go to logout.html???
I've also tried by implementing custom filter (which eventually sets authenticationManager as the property); but still no luck.
I've also checked the log files but nothing in there.
BTW, if I try to access through curl, I get Http status 403 (forbidden). The server understood the request but refuses to authorize it.
curl -i -X POST -d username=admin -d password=Admin123 http://localhost:8080/sts/api/login
Please help me to find out the issue.
Alhamdulillah, finally I've found the issue.The code base which I originally started with was implemented on Spring 2.5. I've upgraded Spring version to 5.1. Basically /j_spring_security_check , j_username and j_password have been deprecated.
Now I've changed my jsp accordingly and it works now.
It's weird that there was no error or warning message.

Can OAuth2 and session based authentication coexist in Spring Security?

I have a web application which uses spring security for session based logins using username and password authentication with the following security application context xml.
<global-method-security pre-post-annotations="enabled" />
<http pattern="/css/**" security="none" />
<http pattern="/files/**" security="none" />
<http auto-config='true' entry-point-ref="authenticationEntryPoint" access-decision-manager-ref="accessDecisionManager">
<intercept-url pattern="/**" access="IS_AUTHENTICATED_ANONYMOUSLY" method="OPTIONS" />
<intercept-url pattern="/login/*" access="IS_AUTHENTICATED_ANONYMOUSLY" />
<intercept-url pattern="/login" access="IS_AUTHENTICATED_ANONYMOUSLY" />
<intercept-url pattern="/**" access="REGISTERED" />
<form-login login-page="/login" login-processing-url="/login_security_check" authentication-failure-handler-ref="xxxAuthenticationFailureHandler" authentication-success-handler-ref="xxxAuthenticationSuccessHandler" />
<logout invalidate-session="true" logout-url="/data/logout" success-handler-ref="xxxLogoutSuccessHandler" />
<remember-me key="xxxRem" />
</http>
<beans:bean id="accessDecisionManager" class="org.springframework.security.access.vote.AffirmativeBased">
<beans:property name="decisionVoters">
<beans:list>
<beans:ref bean="roleVoter" />
<beans:ref bean="authenticatedVoter" />
</beans:list>
</beans:property>
</beans:bean>
<beans:bean id="roleVoter" class="org.springframework.security.access.vote.RoleVoter">
<beans:property name="rolePrefix" value="" />
</beans:bean>
<beans:bean id="authenticatedVoter" class="org.springframework.security.access.vote.AuthenticatedVoter">
</beans:bean>
<beans:bean id="userDetailsService" class="com.xxx.web.security.XXXUserDetailsService">
</beans:bean>
<authentication-manager alias="authenticationManager">
<authentication-provider user-service-ref='userDetailsService'>
<password-encoder hash="md5">
<salt-source user-property="username" />
</password-encoder>
</authentication-provider>
</authentication-manager>
<beans:bean id="loginUrlAuthenticationEntryPoint" class="org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint">
<beans:constructor-arg value="/login" />
</beans:bean>
<beans:bean id="authenticationEntryPoint" class="org.springframework.security.web.authentication.DelegatingAuthenticationEntryPoint">
<beans:property name="defaultEntryPoint" ref="loginUrlAuthenticationEntryPoint" />
</beans:bean>
Now I want to expose my web services for a mobile app, so I am looking to implement OAuth2. I've read the examples provided on github.
I was wondering how these two security flows can co-exist as the intercept url pattern will be same for both the flows?
You would need to change the access="" rules for the resources that are shared between the UI and the OAuth resources. It's not very common for those two to really cross over very much, but I guess for simple apps it might be possible through content negotiation. It's probably easiest to use the SpEL support in XML (or switch to Java config). Example:
<intercept-url pattern="/** access="isFullyAuthenticated() or #oauth2.hasScope('read')"/>
For an alternative approach you could create aliases for your endpoints and protect them with separate filter chains, one for the token and one for cookie-based authentication. Example:
#RequestMapping({ "/user", "/api/user" })
public Map<String, String> user(Principal principal) {
Map<String, String> map = new LinkedHashMap<>();
map.put("name", principal.getName());
return map;
}
where "/user" is protected as a normal resource (i.e. with WebSecurityConfigurerAdapter in Java config), and "/api/user" is separately configured (i.e. with a ResourceServerConfigurerAdapter in Java config).

jasig cas server returning _cas_stateful_ as username with spring

I'm trying to connect from a spring security application to a cas server. When I login in CAS, the request is redirected to my webapp but in my UserDetailsService I'm receiving _cas_stateful_ as the username and I cannot find my user in the webapp to load the permissions
The problem was the authenticationManager. As the documentation says, you must use CasAuthenticationProvider like this:
<beans:bean id="casAuthenticationProvider"
class="org.springframework.security.cas.authentication.CasAuthenticationProvider">
<beans:property name="authenticationUserDetailsService">
<beans:bean
class="org.springframework.security.core.userdetails.UserDetailsByNameServiceWrapper">
<beans:constructor-arg ref="mongoUserDetailsService" />
</beans:bean>
</beans:property>
<beans:property name="serviceProperties" ref="serviceProperties" />
<beans:property name="ticketValidator">
<beans:bean class="org.jasig.cas.client.validation.Cas20ServiceTicketValidator">
<beans:constructor-arg index="0" value="https://localhost:7443/cas" />
</beans:bean>
</beans:property>
<!-- Esta clave es única por aplicación -->
<beans:property name="key" value="your-provider-auth" />
</beans:bean>
Then you must to set the casAuthenticationProvider to the authenticationManager:
<authentication-manager alias="authenticationManager">
<!-- <authentication-provider user-service-ref='mongoUserDetailsService'/> -->
<authentication-provider ref="casAuthenticationProvider" />
</authentication-manager>
As you can see, the custom mongoUserDetailsService is not assigned to the authenticationManager but the new casAuthenticationProvider, then we set the casAuthenticationProvider to the authenticationManager

Spring security oauth 2 simple example

I try to implement my own example based on official tutorial Sparklr2/Tonr2. Everything looks good but when I remove from web.xml in my Tonr2 implementation, spring security filter I have exception:
No redirect URI has been established for the current request
I can't understand what URL should I use. Here is my code, for client implementation:
<!--apply the oauth client context -->
<oauth:client id="oauth2ClientFilter" />
<!--define an oauth 2 resource for sparklr -->
<oauth:resource id="provider" type="authorization_code" client-id="client" client-secret="secret"
access-token-uri="http://localhost:8080/provider/oauth/token" user-authorization-uri="http://localhost:8080/provider/oauth/authorize" scope="read,write" />
<beans:bean id="clientController" class="com.aouth.client.ClientController">
<beans:property name="trustedClientRestTemplate">
<oauth:rest-template resource="provider" />
</beans:property>
</beans:bean>
And for provider:
<http pattern="/oauth/token" create-session="stateless" authentication-manager-ref="clientAuthenticationManager" xmlns="http://www.springframework.org/schema/security">
<intercept-url pattern="/oauth/token" access="IS_AUTHENTICATED_FULLY" />
<anonymous enabled="false" />
<http-basic />
</http>
<authentication-manager id="clientAuthenticationManager" xmlns="http://www.springframework.org/schema/security">
<authentication-provider user-service-ref="clientDetailsUserService" />
</authentication-manager>
<bean id="clientDetailsUserService" class="org.springframework.security.oauth2.provider.client.ClientDetailsUserDetailsService">
<constructor-arg ref="clientDetails" />
</bean>
<!-- The OAuth2 protected resources are separated out into their own block so we can deal with authorization and error handling
separately. This isn't mandatory, but it makes it easier to control the behaviour. -->
<http pattern="/secured" create-session="never" access-decision-manager-ref="accessDecisionManager" xmlns="http://www.springframework.org/schema/security">
<anonymous enabled="false" />
<intercept-url pattern="/secured" access="ROLE_USER,SCOPE_READ" />
<custom-filter ref="resourceServerFilter" before="PRE_AUTH_FILTER" />
<http-basic />
</http>
<bean id="accessDecisionManager" class="org.springframework.security.access.vote.UnanimousBased" xmlns="http://www.springframework.org/schema/beans">
<constructor-arg>
<list>
<bean class="org.springframework.security.oauth2.provider.vote.ScopeVoter" />
<bean class="org.springframework.security.access.vote.RoleVoter" />
<bean class="org.springframework.security.access.vote.AuthenticatedVoter" />
</list>
</constructor-arg>
</bean>
<oauth:resource-server id="resourceServerFilter" resource-id="resource" token-services-ref="tokenServices" />
<bean id="tokenServices" class="org.springframework.security.oauth2.provider.token.DefaultTokenServices">
<property name="tokenStore" ref="tokenStore" />
<property name="supportRefreshToken" value="true" />
<property name="clientDetailsService" ref="clientDetails"/>
</bean>
<bean id="tokenStore" class="org.springframework.security.oauth2.provider.token.InMemoryTokenStore" />
<http auto-config="true" xmlns="http://www.springframework.org/schema/security">
<intercept-url pattern="/test" access="ROLE_USER" />
<intercept-url pattern="/" access="IS_AUTHENTICATED_ANONYMOUSLY" />
</http>
<authentication-manager alias="authenticationManager" xmlns="http://www.springframework.org/schema/security">
<authentication-provider>
<user-service>
<user name="pr" password="pr" authorities="ROLE_USER" />
</user-service>
</authentication-provider>
</authentication-manager>
<oauth:authorization-server client-details-service-ref="clientDetails" token-services-ref="tokenServices" >
<oauth:authorization-code />
<oauth:implicit />
<oauth:refresh-token />
<oauth:client-credentials />
<oauth:password />
</oauth:authorization-server>
<oauth:client-details-service id="clientDetails">
<oauth:client client-id="client" resource-ids="resource" authorized-grant-types="authorization_code, implicit"
authorities="ROLE_CLIENT" scope="read,write" secret="secret" />
</oauth:client-details-service>
I just want my client to work without spring security. And when I need my protected resource I want to login only on provider side.
You 2nd XML that you pasted here is the spring's XML for the oauth-provider and the protected-resource, which in your case run in the same webapp. (you can separate them, of course, if you wish).
The client (the 1st pasted-XML) is a different story. If I understand you correctly, you want your client to run without Spring's help (to be a regular webapp, and not spring-security-oauth-client webapp).
You have to understand how oAuth works: the client tries to get to a protected resource; if it does not have the access-token, it is being redirected to the oAuth-provider (that shows the login page and supplies the token). By the standard, the request for the access-token MUST contain a "redirect-uri" param, so after a successful login, the oAuth-provider knows where to redirect the client to. The oAuth client does it for you, and if you delete the "oauth client" from your web.xml, you now have to implement this by yourself.
Thanks for your answer. But I still don't understand how spring
security influences my oAuth client. And can I use for client side
spring-oauth (spring-mvc) without spring-security?
When you write this line in your XML:
< oauth:client id="oauth2ClientFilter" />
it means that you use spring-security-oauth, which is a package dedicated for oauth, built on spring-security. If you dig in, it puts a special filter (OAuth2ClientContextFilter) in the chain that handles the oAuth stuff, that are relevant for the client. One of them is sending the request with all the params ("redirect-uri" is one of them).
If you decide NOT to use spring-security-oauth, well - you will have to implement this logic by yourself...
Hope that helps!

Mapping each http block to a specific Authentication Provider

I would like to base my Spring Security configuration depending on the user's context path. If the user goes against a url with http://path1/resource1 I would like to direct them to a specific authentication provider. If they come in on http://path2/resource2 I would like to direct them to a different authentication provider. These url paths are REST based web services calls so that's why they're stateless and not coming from a form. Currently, all authentication providers get executed. What is the best approach for this situation? I'm using spring-security 3.1.0.M1.
<http pattern="/path1/**" create-session="stateless">
<intercept-url pattern="/**" access="ROLE_USER,ROLE_VAR,ROLE_ADMIN" />
<http-basic />
</http>
<http pattern="/path2/**" create-session="stateless">
<intercept-url pattern="/**" access="ROLE_USER,ROLE_VAR,ROLE_ADMIN" />
<http-basic />
</http>
You can define an authentication-manager reference in each http block:
<http pattern="/api/**" authentication-manager-ref="apiAccess">
...
</http>
<http auto-config = "true" authentication-manager-ref="webAccess">
...
</http>
<!-- Web authentication manager -->
<authentication-manager id="webAccess">
<authentication-provider
user-service-ref="userService">
</authentication-provider>
</authentication-manager>
<!-- API authentication manager -->
<authentication-manager id="apiAccess">
<authentication-provider
user-service-ref="developerService">
</authentication-provider>
</authentication-manager>
This feature has been added in Spring Security 3.1.
This works for me:
<security:authentication-manager alias="basicAuthenticationManager">
<security:authentication-provider user-service-ref="accountService">
<security:password-encoder hash="sha"/>
</security:authentication-provider>
<security:authentication-provider user-service-ref="accountService"/>
</security:authentication-manager>
<bean id="basicProcessingFilter" class="org.springframework.security.web.authentication.www.BasicAuthenticationFilter">
<property name="authenticationManager">
<ref bean="basicAuthenticationManager" />
</property>
<property name="authenticationEntryPoint">
<ref bean="basicProcessingEntryPoint" />
</property>
</bean>
<bean id="basicProcessingEntryPoint"
class="com.yourpackage.web.util.CustomBasicAuthenticationEntryPoint">
<property name="realmName" value="yourRealm" />
</bean>
<!-- Stateless RESTful service using Basic authentication -->
<security:http pattern="/rest/**" create-session="stateless" entry-point-ref="basicProcessingEntryPoint">
<security:custom-filter ref="basicProcessingFilter" position="BASIC_AUTH_FILTER" />
<security:intercept-url pattern="/rest/new" access="IS_AUTHENTICATED_ANONYMOUSLY" />
<security:intercept-url pattern="/rest/**" access="ROLE_USER" />
</security:http>
<!-- Additional filter chain for normal users, matching all other requests -->
<security:http use-expressions="true">
<security:intercept-url pattern="/index.jsp" access="permitAll" />
<security:intercept-url pattern="/**" access="hasRole('ROLE_USER')" />
<security:form-login login-page="/signin"
authentication-failure-url="/signin?signin_error=1"
default-target-url="/"
always-use-default-target="true"/>
<security:logout />
</security:http>
I implemented the authentication entry point because I needed to send some special error codes in certain situations but you don't need to do so.

Resources