Spring security OpenID flow using JWT for authentication - java

I am trying to do authentication for my web application using widely used OpenId Connect flow.
I understand that the user who wants to authenticate on example1.com will first be redirected to the authentication server (or OP : "OpenId Provider"). The user authenticates on that server which then redirects him back to the original example1.com site with a signed JWT token.
Technical challenges:
I am suing spring security as part of my web application. I took a custom filter to redirect the user to authentication server and then it redirects back to my example1.com with valid JWT (Json Web Token).
My Custom Filter:
public class MyCustomFilter extends AbstractAuthenticationProcessingFilter {
#Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
throws AuthenticationException, IOException, ServletException {
//reading the AWT access token from reqest beahder
String token = request.getHeader("Authorization");
if(token == null){
// redirecting user to authentication server
String accessCodeUrl = "authentication.com?query string"
response.sendRedirect(accessCodeUrl);
} else{
response.addHeader("Authorization", token);
}
//Now how can i inject the above received token to spring security
}
}
My spring xml config:
<security:http auto-config="false" entry-point-ref="entryPoint" disable-url-rewriting="true">
<!-- set disabled to true to remove Cross Site Request Forger support -->
<security:csrf disabled="true" />
<security:intercept-url pattern="/**" access="hasAnyRole('ROLE_USER','ROLE_ADMIN')" />
<security:custom-filter ref="${MyCustomFilter }" position="PRE_AUTH_FILTER" />
<security:access-denied-handler error-page="${security.accessDeniedPage}"/>
<security:headers>
<security:frame-options policy="SAMEORIGIN"/>
</security:headers>
</security:http>
My custom filter is extending AbstractAuthenticationProcessingFilter. is it good fit for my requirement or should i consider extending any other filter's like BasicAuthenticationFilter or OncePerRequestFilter or GenericFilterBean.
I am confused here as to take 1 or 2 filters. because first time i am redirecting to authorization server, but from second time i should use the JWT token provided by authentication server.
Since i am going with stateless approach. I need to exchange JWT token every time between example.com and browser. I am using ExtJs as front end, what is the best practice to exchange JWT token between browser and example.com.
As per my understanding i should send JWT token every time from browser along with every request. Does that mean should i manually inject every time JWT token as part of Ajax request or Do we have some approach to append to all the outgoing Ajax requests.

Related

Spring Security logout GET vs POST

I'm using Spring Boot and Spring Security. I have 2 apps. They works in couple. And when I want to logout from one, it should also logout from another. I use default logout flow. On application A I click logout link:
<logout invalidate-session="true" delete-cookies="JSESSIONID" logout-success-url="/app-b-logout" />
#RequestMapping("/app-b-logout")
public RedirectView appB_Logout() {
return new RedirectView("http://appB/logout");
}
On application B I have following settings:
.logout().permitAll().logoutUrl("/logout")
And logout success handler:
public class MyLogoutSuccessHandler extends AbstractAuthenticationTargetUrlRequestHandler
implements LogoutSuccessHandler {
#Override
public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
System.out.println(authentication == null); // MAGIC HERE
}
}
And in line System.out.println(authentication == null); I have different results. If I redirect from application A, authentication is null, when I click LOGOUT button on app B (using post form), I have authentication object.
But in both cases user is logged out in result. But I need to do some stuff with authentication object. How to make redirect on app A to make a POST request or just how to get this authentication when I redirect from app A?

How exactly works this Spring Security example?

I am pretty new in Spring Security and I have some doubt related the configuration found into a tutorial.
This is the spring-security.xml file used to the Spring Security configuration into the project:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:security="http://www.springframework.org/schema/security"
xsi:schemaLocation="http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-4.0.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<security:http>
<security:intercept-url pattern="/springLogin" access="permitAll"/>
<security:intercept-url pattern="/doSpringLogin" access="permitAll"/>
<security:intercept-url pattern="/myprofile" access="hasRole('ROLE_USER')"/>
<security:intercept-url pattern="/springHome" access="hasRole('ROLE_USER')"/>
<security:intercept-url pattern="/products" access="hasRole('ROLE_USER')"/>
<security:intercept-url pattern="/springLogout" access="permitAll"/>
<security:intercept-url pattern="/springLogin?error=true" access="permitAll"/>
<security:form-login login-page="/springLogin" login-processing-url="/doSpringLogin"
default-target-url="/springHome" authentication-failure-url="/springLogin?error=true"
username-parameter="username" password-parameter="password"
/>
<security:csrf disabled="true"/>
<security:logout logout-url="/springLogout" logout-success-url="/springLogin"/>
</security:http>
<bean id="userDetailsServiceImpl" class="com.demo.security.UserDetailsServiceImpl"></bean>
<bean id="authenticationProvider" class="org.springframework.security.authentication.dao.DaoAuthenticationProvider">
<property name="userDetailsService" ref="userDetailsServiceImpl"></property>
</bean>
<bean id="authenticationManager" class="org.springframework.security.authentication.ProviderManager">
<constructor-arg name="providers">
<list>
<ref bean="authenticationProvider"/>
</list>
</constructor-arg>
</bean>
<security:authentication-manager>
<security:authentication-provider user-service-ref="userDetailsServiceImpl">
<security:password-encoder hash="plaintext"></security:password-encoder>
</security:authentication-provider>
</security:authentication-manager>
</beans>
I it divided into some section. The first one is the tag content.
It contains something as:
<security:intercept-url pattern="/springLogin" access="permitAll"/>
that I think means that the page related to the /springLogin resource is accessible to everyone while
<security:intercept-url pattern="/myprofile" access="hasRole('ROLE_USER')"/>
means that the resource related to the /myprofile resource is accessible only to the logged user (the principal) having a ROLE_USER role setted.
Is it this reasoning correct?
Then in the previous configuration file there is:
1) The declaration of the authenticationManager bean:
<bean id="authenticationManager" class="org.springframework.security.authentication.ProviderManager">
<constructor-arg name="providers">
<list>
<ref bean="authenticationProvider"/>
</list>
</constructor-arg>
</bean>
that I think it is used by Spring to populate the SecurityContext with the Principal objects (for example all the user of a web application) and with the Authorities (what a specific Principal can do).
Is this reasoning correct?
This object take as constructor arg a list of autentication provider bean that have to provide the Principal informations (so for example the role associated to a specific Principal)
In this case is provided an implementation of the DaoAuthenticationProvider class that take a bean having name="userDetailsService" as property, this one:
<bean id="userDetailsServiceImpl" class="com.demo.security.UserDetailsServiceImpl"></bean>
that is an instance of the UserDetailsServiceImpl class, this one:
public class UserDetailsServiceImpl implements UserDetailsService {
#Override
public UserDetails loadUserByUsername(String username)
throws UsernameNotFoundException {
System.out.println(username);
User user = RegisteryDAO.getUserDAO().getUserByUsername(username);
if(user == null){
return null;
}
List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
authorities.add(new SimpleGrantedAuthority(user.getRole()));
UserDetails userDetails = new org.springframework.security.core.userdetails.
User(user.getUsername(), user.getPassword(), true, true, true, true, authorities);
return userDetails;
}
}
So what exactly happen?
Using the debugger it seems to me that when te user try to access to a specific page this loadUserByUsername() return the UserDetails object related to the logged user that contain the List representing the roles associated to the specific logged user (for example the previous ROLE_USER)
Then I think that Spring automatically use the
<security:intercept-url pattern="/myprofile" access="hasRole('ROLE_USER')"/>
to check if the user have setted the propper role into the previous List list.
If it have so forward the request to the controller method that handle this Http Request otherwise avoid that this HttpRequest come to this controller method and show a page that say that the user can't access to this resource.
Here is an explanation of some of the concepts and questions you are asking about.
AuthenticationManager
AuthenticationManager is the component responsible for processing the Authentication request. The Authentication request might be instance of UsernamePasswordAuthenticationToken for username/password logins.
For other implementations look at Authentication JavaDoc.
AuthenticationManager also has collection of AuthenticationProvider implementations. These components are capable of processing specific Authentication types and AuthenticationManager iterates through them attempting to find one capable of handling the Authentication passed to it. If it finds one, it calls it with Authentication object presented and returns fully populated Authentication object if successful (otherwise AuthenticationException is thrown).
AuthenticationProvider
As mentioned above, AuthenticationProvider processes certain type of Authentication request. For instance the DaoAuthenticationProvider will perform following steps when called by AuthenticationManager:
Take the UsernamePasswordAuthenticationToken passed to it
Use the UserDetailsService service implementation provided to it (in your case it is UserDetailServiceImpl) to look up user by username
Check the password provided in the authentication token against the user using PasswordEncoder and SaltSource, if specified.
If the authentication succeeds, returns the populated Authentication object (UsernamePasswordAuthenticationToken in this case), which contains principal, credentials and is marked as authenticated
In case the authentication fails, AuthenticationException will be thrown
DaoAuthenticationProvider which you are using which is capable of processing UsernamePasswordAuthenticationToken requests. So typically form logins, and so on. You can see which types of authentications provider support by looking at its supports() method implementation, which in case of DaoAuthenticationProvider looks like this:
public boolean supports(Class<?> authentication) {
return (UsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication));
}
Spring Security Filter Chain
Now let's look at the Security filter chain, as defined by Spring Security documentation:
The order that filters are defined in the chain is very important.
Irrespective of which filters you are actually using, the order should
be as follows:
ChannelProcessingFilter, because it might need to redirect to a different protocol
SecurityContextPersistenceFilter, so a SecurityContext can be set up in the SecurityContextHolder at the beginning of a web request, and
any changes to the SecurityContext can be copied to the HttpSession
when the web request ends (ready for use with the next web request)
ConcurrentSessionFilter, because it uses the SecurityContextHolder functionality but needs to update the SessionRegistry to reflect
ongoing requests from the principal
Authentication processing mechanisms - UsernamePasswordAuthenticationFilter, CasAuthenticationFilter,
BasicAuthenticationFilter etc - so that the SecurityContextHolder can
be modified to contain a valid Authentication request token
The SecurityContextHolderAwareRequestFilter, if you are using it to install a Spring Security aware HttpServletRequestWrapper into your
servlet container
RememberMeAuthenticationFilter, so that if no earlier authentication processing mechanism updated the SecurityContextHolder,
and the request presents a cookie that enables remember-me services to
take place, a suitable remembered Authentication object will be put
there
AnonymousAuthenticationFilter, so that if no earlier authentication processing mechanism updated the SecurityContextHolder,
an anonymous Authentication object will be put there
ExceptionTranslationFilter, to catch any Spring Security exceptions so that either an HTTP error response can be returned or an
appropriate AuthenticationEntryPoint can be launched
FilterSecurityInterceptor, to protect web URIs and raise exceptions when access is denied
When the user submits login form, AuthenticationManager is called at step 4 in the filter chain. In the case of form login it would be handled by UsernamePasswordAuthenticationFilter which calls the AuthenticationManager to process the authentication:
public Authentication attemptAuthentication(HttpServletRequest request,
HttpServletResponse response) throws AuthenticationException {
// ...
return this.getAuthenticationManager().authenticate(authRequest);
}
Using the debugger it seems to me that when te user try to access to a specific page this loadUserByUsername() return the UserDetails
Actually the loadUserByUsername() is called when user authenticates, for instance after submitting login form. If the user is already authenticated this is not called.
I think that means that the page related to the /springLogin resource is accessible to everyone:
<security:intercept-url pattern="/springLogin" access="permitAll" />
Then I think that Spring will automatically use following to check if the user has proper role:
<security:intercept-url pattern="/myprofile" access="hasRole('ROLE_USER')" />
Correct. This process is handled by FilterSecurityInterceptor, which extends AbstractSecurityInterceptor - core Spring Security component dealing with authorization. If the user is not authenticated or doesn't have the required role an Exception is thrown and handled by the ExceptionTranslationFilter. This filter handles Security exceptions. For instance in case of authentication failure it will redirect user to authentication entry point, e.g. the login page.
Internal architecture of Spring Security is pretty nicely described in the reference documentation. I recommend to take a look at it.

Do not redirect user after auth failed with BasicAuthenticationFilter

I have two way user can authenticate on my system. Standart with login password and using BasicAuthentication for API calls. When standart auth failed, I send redirect to login page, but when BasicAuth failed I want to return json response.
I also have custom AccessDecisionManager defined and after WebExpressionVoter returns access_denied, the AccessDeniedException is being thrown and in rest client I see html code of main page.
How should I configure my spring security, to return json response?
Thanks
You should implement custom org.springframework.security.web.access.AccessDeniedHandler which sends JSON response as you need from its handle method. The handle is called automatically whenever AccessDecisionManager denies access.
You then add instance of your class as a bean in the Spring Security configuration and refer to it from your API's <security:http> definition as follows:
<security:http pattern="/API/**">
<security:http-basic />
<security:access-denied-handler ref="myDeniedHandler"/>
</security:http>

Redirect to the original URL after signin using Spring Social, Spring security?

Spring social and security experts,
I have the following use case:
User requests a specific URL like http://www.foobar.com/foo/1001
Anonymous user can see this page but cannot post a comment in this page. Comment posting part is secured by Spring security.
User clicks login. It pops up a login window or redirect it to login page.
The user chooses to sign in with Facebook ID.
After user signed in using FB, it redirects the user to http://www.foobar.com/foo/1001 with authorization.
I was wondering how I can do that using Spring Social. Thanks a lot!!
Have you actually tried it to see if it works? Spring security does this automatically.
If you are an anonymous user and attempt to access a resource that requires a certain permission, spring security will store the attempted URL and redirect you to the login page. After successful login it fetches the attempted URL back and redirects you there.
I have only managed to do this by copy/pasting code which spring security uses to do this job.
CAVEAT: I am using ProviderSignInController to provision accounts and sign in.
ProviderSignInController permits the use of a SignInAdapter to manually login local user account based on the SocialConnection
In the signIn method:
public String signIn(String userId, Connection<?> connection, NativeWebRequest request)
I have the following code:
HttpServletRequest req = (HttpServletRequest)request.getNativeRequest();
HttpServletResponse resp = (HttpServletResponse)request.getNativeResponse();
RequestCache rc = new HttpSessionRequestCache();
SavedRequest savedRequest = rc.getRequest(req, resp);
String targetUrl = savedRequest.getRedirectUrl();
if(targetUrl != null){
log.info("Redirecting to DefaultSavedRequest Url: " + targetUrl);
new DefaultRedirectStrategy().sendRedirect(req, resp, targetUrl);
hasSentRedirect = true;
}
I had to dig through the code of SavedRequestAwareAuthenticationSuccessHandler to see how this works as part of spring security.
I am disappointed that ProviderSignInController isn't really linked to Spring Security at all. And so we must hack our way around to get the same functionality.
I have also found that login events aren't posted either.
I have asked about this recently: Should I use both SocialAuthenticationFilter and ProviderSignInController together

RESTful Authentication via Spring

Problem:
We have a Spring MVC-based RESTful API which contains sensitive information. The API should be secured, however sending the user's credentials (user/pass combo) with each request is not desirable. Per REST guidelines (and internal business requirements), the server must remain stateless. The API will be consumed by another server in a mashup-style approach.
Requirements:
Client makes a request to .../authenticate (unprotected URL) with credentials; server returns a secure token which contains enough information for the server to validate future requests and remain stateless. This would likely consist of the same information as Spring Security's Remember-Me Token.
Client makes subsequent requests to various (protected) URLs, appending the previously obtained token as a query parameter (or, less desirably, an HTTP request header).
Client cannot be expected to store cookies.
Since we use Spring already, the solution should make use of Spring Security.
We've been banging our heads against the wall trying to make this work, so hopefully someone out there has already solved this problem.
Given the above scenario, how might you solve this particular need?
We managed to get this working exactly as described in the OP, and hopefully someone else can make use of the solution. Here's what we did:
Set up the security context like so:
<security:http realm="Protected API" use-expressions="true" auto-config="false" create-session="stateless" entry-point-ref="CustomAuthenticationEntryPoint">
<security:custom-filter ref="authenticationTokenProcessingFilter" position="FORM_LOGIN_FILTER" />
<security:intercept-url pattern="/authenticate" access="permitAll"/>
<security:intercept-url pattern="/**" access="isAuthenticated()" />
</security:http>
<bean id="CustomAuthenticationEntryPoint"
class="com.demo.api.support.spring.CustomAuthenticationEntryPoint" />
<bean id="authenticationTokenProcessingFilter"
class="com.demo.api.support.spring.AuthenticationTokenProcessingFilter" >
<constructor-arg ref="authenticationManager" />
</bean>
As you can see, we've created a custom AuthenticationEntryPoint, which basically just returns a 401 Unauthorized if the request wasn't authenticated in the filter chain by our AuthenticationTokenProcessingFilter.
CustomAuthenticationEntryPoint:
public class CustomAuthenticationEntryPoint implements AuthenticationEntryPoint {
#Override
public void commence(HttpServletRequest request, HttpServletResponse response,
AuthenticationException authException) throws IOException, ServletException {
response.sendError( HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized: Authentication token was either missing or invalid." );
}
}
AuthenticationTokenProcessingFilter:
public class AuthenticationTokenProcessingFilter extends GenericFilterBean {
#Autowired UserService userService;
#Autowired TokenUtils tokenUtils;
AuthenticationManager authManager;
public AuthenticationTokenProcessingFilter(AuthenticationManager authManager) {
this.authManager = authManager;
}
#Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
#SuppressWarnings("unchecked")
Map<String, String[]> parms = request.getParameterMap();
if(parms.containsKey("token")) {
String token = parms.get("token")[0]; // grab the first "token" parameter
// validate the token
if (tokenUtils.validate(token)) {
// determine the user based on the (already validated) token
UserDetails userDetails = tokenUtils.getUserFromToken(token);
// build an Authentication object with the user's info
UsernamePasswordAuthenticationToken authentication =
new UsernamePasswordAuthenticationToken(userDetails.getUsername(), userDetails.getPassword());
authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails((HttpServletRequest) request));
// set the authentication into the SecurityContext
SecurityContextHolder.getContext().setAuthentication(authManager.authenticate(authentication));
}
}
// continue thru the filter chain
chain.doFilter(request, response);
}
}
Obviously, TokenUtils contains some privy (and very case-specific) code and can't be readily shared. Here's its interface:
public interface TokenUtils {
String getToken(UserDetails userDetails);
String getToken(UserDetails userDetails, Long expiration);
boolean validate(String token);
UserDetails getUserFromToken(String token);
}
That ought to get you off to a good start.
You might consider Digest Access Authentication. Essentially the protocol is as follows:
Request is made from client
Server responds with a unique nonce string
Client supplies a username and password (and some other values) md5 hashed with the nonce; this hash is known as HA1
Server is then able to verify client's identity and serve up the requested materials
Communication with the nonce can continue until the server supplies a new nonce (a counter is used to eliminate replay attacks)
All of this communication is made through headers, which, as jmort253 points out, is generally more secure than communicating sensitive material in the url parameters.
Digest Access Authentication is supported by Spring Security. Notice that, although the docs say that you must have access to your client's plain-text password, you can successfully authenticate if you have the HA1 hash for your client.
Regarding tokens carrying information, JSON Web Tokens (http://jwt.io) is a brilliant technology. The main concept is to embed information elements (claims) into the token, and then signing the whole token so that the validating end can verify that the claims are indeed trustworthy.
I use this Java implementation: https://bitbucket.org/b_c/jose4j/wiki/Home
There is also a Spring module (spring-security-jwt), but I haven't looked into what it supports.
Why don't you start using OAuth with JSON WebTokens
http://projects.spring.io/spring-security-oauth/
OAuth2 is an standardized authorization protocol/framework. As per Official OAuth2 Specification:
You can find more info here

Categories

Resources