Reputation: 43057
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.
Upvotes: 4
Views: 1437
Reputation: 34826
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
:
UsernamePasswordAuthenticationToken
passed to itUserDetailsService
service implementation provided to it (in your case it is UserDetailServiceImpl
) to look up user by usernamePasswordEncoder
and SaltSource
, if specified.UsernamePasswordAuthenticationToken
in this case), which contains principal, credentials and is marked as authenticated
AuthenticationException
will be thrownDaoAuthenticationProvider
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));
}
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 principalAuthentication processing mechanisms -
UsernamePasswordAuthenticationFilter
,CasAuthenticationFilter
,BasicAuthenticationFilter
etc - so that theSecurityContextHolder
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 theUserDetails
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.
Upvotes: 3