I am implementing Spring SAML in my web app which already has spring security implemented, due to which I have 2 authentication managers now. As spring always refer to the last declared authenticationManager, I found the solution to define one authenticationManager as a bean.
Following was my AuthenticationManager before conversion to bean:
<authentication-manager alias="samlAuthenticationManager">
<!-- Register authentication manager for SAML provider -->
<authentication-provider ref="samlAuthenticationProvider"/>
<!-- Register authentication manager for administration UI -->
<authentication-provider>
<user-service id="adminInterfaceService">
<user name="admin" password="admin" authorities="ROLE_ADMIN"/>
</user-service>
</authentication-provider>
</authentication-manager>
Following is my code after converting to bean:
<beans:bean id="samlAuthenticationManager" class="org.springframework.security.authentication.ProviderManager">
<beans:constructor-arg>
<beans:list>
<beans:bean class="org.springframework.security.saml.SAMLAuthenticationProvider">
<beans:property name="userDetails" value="adminInterfaceService"/>
</beans:bean>
</beans:list>
</beans:constructor-arg>
</beans:bean>
<user-service id="adminInterfaceService">
<user name="admin" password="admin" authorities="ROLE_ADMIN"/>
</user-service>
Authentication provider is defines as follows:
<beans:bean id="samlAuthenticationProvider" class="org.springframework.security.saml.SAMLAuthenticationProvider">
<!-- OPTIONAL property: can be used to store/load user data after login -->
<!--
<beans:property name="userDetails" ref="bean" />
-->
</beans:bean>
I am getting following exception:
Cannot convert value of type 'java.lang.String' to required type
'org.springframework.security.saml.userdetails.SAMLUserDetailsService'
for property 'userDetails'
Please help regarding the same. I will be highly obliged.
Thanks in advance
Found the solution here
https://github.com/spring-projects/spring-security/issues/2163
Just had to use id instead of alias in both the authentication-manager
You shouldn't need to use Spring beans. If you don't specify an ID,
you will override the "default" instance. That's pretty much the way
standard Spring beans work. In the referenced thread, the user is
specifying an alias, rather than an ID, so that doesn't create a
separate instance. Again that's the way normal bean instances work, so
I'm not sure we should deviate from that.
Related
The problem is that my custom Spring Security filter is never invoked when a request comes in. During debugging, I found that in doFilter() in FilterChainProxy, my filter (JwtAuthenticationFilter) can be fetched:
But it's skipped. Then I found it's due to:
So the superclass of my filer, which is AbstractAuthenticationProcessingFilter thinks the request doesn't need authentication and it just calls doFilter() to pass it down. I think my configs specified that auth is needed. This specific request is /ui/home/index.jsp, where \ui is the context.
My security configs:
<http use-expressions="true" pattern="/**" entry-point-ref="JwtAuthenticationEntryPoint" create-session="stateless">
<custom-filter before="CONCURRENT_SESSION_FILTER" ref="jwtAuthenticationFilter" />
<intercept-url pattern="/home/**" access="isAuthenticated()"/>
// some other intercept-url definitions
</http>
<authentication-manager alias="authenticationManager">
<authentication-provider ref="authenticationProvider"/>
</authentication-manager>
And bean configs:
<bean id="jwtAuthenticationFilter" class="com.pk.jjwt.JwtAuthenticationTokenFilter" >
<property name="authenticationManager" ref="authenticationManager"/>
<property name="authenticationSuccessHandler" ref="jwtAuthenticationSuccessHandler" />
</bean>
<bean id="JwtAuthenticationEntryPoint" class="com.pk.jjwt.JwtAuthenticationEntryPoint" />
<bean id="authenticationProvider" class="com.pk.jjwt.JwtAuthenticationProvider" />
<bean id="jwtAuthenticationSuccessHandler" class="com.pk.jjwt.JwtAuthenticationSuccessHandler" />
I wonder what might cause the filters getting skipped? I think I specified that every url pattern needs to be authenticated. I'm not sure why it thinks that request doesn't need authentication from my custom filter.
Edit:
So I debugged the requiresAuthentication() method, and found:
Basically it's evaluating uri.endsWith("/ui/**") and uri is /ui/home/index.jsp. It returned false, so the filter is skipped.
I have the following configuration in my spring security xml file. When I try to authenticate I get the following message but cannot proceed.
INFO: Ignoring PartialResultException
I am aware that spring's documentation states that you can set ignorePartialResultException to true but this property seems to be in the LdapTemplate class which may require additional coding. I would like to accomplish all of this through bean configuration as I am not interested in role mapping.
<authentication-manager>
<authentication-provider ref="activeDirectoryAuthProvider" />
</authentication-manager>
<beans:bean id="activeDirectoryAuthProvider"
class="org.springframework.security.ldap.authentication.ad.ActiveDirectoryLdapAuthenticationProvider">
<beans:constructor-arg value="mydomain.com" />
<beans:constructor-arg value=" ldap://mydomain.com:389" />
</beans:bean>
After digging around we found out that our role mapping was blocking the authentication. We were in fact hitting AD but Spring was trying to map a group name to a role that didn't exist within our system. Once we did that we were good to go.
I'm using spring security to manage user log in/signup in my project. I need to implement user lockout functionality after three failed log in attempts.What I did is to add another field 'account_non_locked' in 'Users' table in database.
The problem I'm facing is that spring security does not update that newly added column. I digged into the source code and found in the default UserDetailsManager the sql statement is written as:
"insert into users (username, password, enabled) values (?,?,?)"
which explains why it does not recognized my new column.
So I copy that file and change it to fit my own need, which is CustomUserDetailsManager.java
Now I can't configure spring security to use my own customized UserDetailsManager. The configuration file right now is:
<authentication-manager alias="authenticationManager">
<authentication-provider>
<password-encoder ref="passwordEncoder" />
<jdbc-user-service id="userDetailsService" data-source-ref="dataSource" />
</authentication-provider>
</authentication-manager>
<beans:bean id="passwordEncoder" class="org.springframework.security.crypto.password.StandardPasswordEncoder" />
I can't find any examples online that will configure this properly. Please help and thanks in advance!
The section 3.2.4 Using other Authentication Providers covers how to do this using authentication-provider#user-service-ref.
Your example would look something like the following:
<authentication-manager alias="authenticationManager">
<authentication-provider user-service-ref="customUserDetailsManager">
<password-encoder ref="passwordEncoder" />
</authentication-provider>
</authentication-manager>
<beans:bean id="passwordEncoder"
class="org.springframework.security.crypto.password.StandardPasswordEncoder" />
<beans:bean id="customUserDetailsManager"
class="com.example.CustomUserDetailsManager">
<!-- additional properties -->
</beans:bean>
I have created a web service in my machine. Its URL is
http://localhost:8080/aaa/test?wsdl
I want to enable one feature to it. As soon as the user enters the url in browser, it should ask for the credentials. Can it be done in web services.
If yes, can some one guide how to achieve it.
Thanks.
If you're already using Spring, you can easily apply basic authentication to a specific URL pattern with Spring Security. In your applicationContext.xml, just add:
<beans:beans xmlns="http://www.springframework.org/schema/security"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-3.0.3.xsd">
<!-- HTTP basic authentication in Spring Security -->
<http>
<intercept-url pattern="/*wsdl?" access="ROLE_USER" />
<http-basic />
</http>
<authentication-manager>
<authentication-provider>
<user-service>
<user name="someUser" password="somePassword" authorities="ROLE_USER" />
</user-service>
</authentication-provider>
</authentication-manager>
</beans:beans>
Example taken from Mkyong's Spring Security HTTP Basic Authentication Example.
If you'd like to lookup users in a database, you'd need to use a different authentication provider. The Spring Security reference mentions data-source-ref if you'd like to query the standard Spring Security user data tables. If you've already got your own structure, you might be interested in using user-service-ref instead, in which you can lookup the users yourself.
<authentication-manager>
<authentication-provider user-service-ref='myUserDetailsService'/>
</authentication-manager>
<beans:bean id="myUserDetailsService"
class="mypackage.MyUserDetailsService">
<beans:property name="dataSource" ref="dataSource"/>
</beans:bean>
And code mypackage.MyUserDetailsService extending JdbcDaoImpl and implementing UserDetailsService.
I was referring to this thread, and in the second last post by Rob Winch (Spring Security Lead), he mentions that we can have access to the sessionRegisty :
<session-management>
<concurrency-control session-registry-alias="sessionRegistry"/>
</session-management>
Therefore, I register the HttpSessionEventPublisher filter in web.xml and specify the above setting in my <http> section. I DON'T add this :
<beans:bean id="sessionRegistry" class="org.springframework.security.core.session.SessionRegistryImpl" />
and in my class, I inject an instance of sessionRegistry like this :
#Autowired
private SessionRegistry sessionRegistry
This is how I am trying to find out the sessions for a user:
List<SessionInformation> userSessions = sessionRegistry.getAllSessions(username,false);
for (SessionInformation userSession : userSessions){
userSession.expireNow();
}
The principal is the username of the user. Upon debugging, the sessionRegistry variable's principals and sessionids variables are empty.
Am I doing anything wrong here, or are the steps mentioned by krams's blog, the only way to do this ?
Well you can autowire sessionRegistry. Nothing is wrong. I used it to track SessionInformation and registered sessions for UserPrincipal
It only worked for me if I changed session-registry-alias to session-registry-ref,and then defined the default impl:
<security:session-management>
<security:concurrency-control max-sessions="10" session-registry-ref="sessionRegistry"/>
</security:session-management>
<bean id="sessionRegistry" class="org.springframework.security.core.session.SessionRegistryImpl"/>
Well it depends which version of spring security you use.
In Spring Security 3.0 it is enough to have the configuration as follows:
<security:session-management>
<security:concurrency-control max-sessions="1"/>
</security:session-management>
Because internally there is used class ConcurrentSessionControlStrategy which invokes registerNewSession on sessionRegistry object.
In Spring Security 3.2 it is different and you have to use more verbose configuration. There is an example in the Spring Security reference doc
The most important part to have sessionRegistry filled with data is the following:
<beans:bean id="sas" class="org.springframework.security.web.authentication.session.CompositeSessionAuthenticationStrategy">
<beans:constructor-arg>
<beans:list>
<beans:bean class="org.springframework.security.web.authentication.session.ConcurrentSessionControlAuthenticationStrategy">
<beans:constructor-arg ref="sessionRegistry"/>
<beans:property name="maximumSessions" value="1" />
</beans:bean>
<beans:bean class="org.springframework.security.web.authentication.session.RegisterSessionAuthenticationStrategy">
<beans:constructor-arg ref="sessionRegistry"/>
</beans:bean>
</beans:list>
</beans:constructor-arg>
</beans:bean>
<beans:bean id="sessionRegistry"
class="org.springframework.security.core.session.SessionRegistryImpl" />
The registration of a new session in sessionRegistry is performed in RegisterSessionAuthenticationStrategy class.
Hopefully it will help you.
Too long for comment, so I answer.
Turn Spring Security debugging on (add to log4j.properties line log4j.logger.org.springframework.security=DEBUG). This should be standard procedure in such problems, as debugging prints many handy information that can show were the problem is.
Can you debug if public void registerNewSession(String sessionId, Object principal) method inside SessionRegistryImpl is called after logging? If not that means HttpSessionEventPublisher is not set up correctly.
You use #Autowired private SessionRegistry sessionRegistry; in your class, dont't you?
EDIT: Can you check if there are any principals in registry?
List<Object> userSessions = sessionRegistry.getAllPrincipals();
where Objects are principals instances you use.