Spring Security SessionRegistry with PersistentTokenBasedRememberMeServices - spring-security

My application's sequrity system is based on Spring Sequrity 3.1. I am using PersistentTokenBasedRememberMeServices.
I need to display a list of all logged users using Sessionregistrympl. The problem is that when the site goes "rememberme-user", it's session does not exist in SessionRegistry.
My configuration files:web.xml
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
<listener>
<listener-class>
org.springframework.security.web.session.HttpSessionEventPublisher
</listener-class>
and spring-sequrity.xml:
<s:http auto-config="false" entry-point-ref="authenticationEntryPoint" >
<s:custom-filter position="FORM_LOGIN_FILTER" ref="authenticationFilter"/>
<s:custom-filter position="REMEMBER_ME_FILTER" ref="rememberMeFilter" />
<s:custom-filter position="CONCURRENT_SESSION_FILTER" ref= "concurrencyFilter" />
<s:custom-filter position="LOGOUT_FILTER" ref="logoutFilter" />
<s:intercept-url pattern="/admin/**/" access="ROLE_ADMIN"/>
<s:intercept-url pattern="/**/" access="ROLE_USER, ROLE_GUEST"/>
<s:anonymous username="guest" granted-authority="ROLE_GUEST" />
</s:http>
<bean
id="logoutFilter"
class="org.springframework.security.web.authentication.logout.LogoutFilter"
p:filterProcessesUrl="/logout/">
<constructor-arg value="/login/" />
<constructor-arg>
<list>
<ref bean="rememberMeServices" />
<bean class="org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler" p:invalidateHttpSession="true"/>
</list>
</constructor-arg>
</bean>
<bean id="authenticationEntryPoint"
class="org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint"
p:loginFormUrl="/login/"/>
<bean id="customAuthenticationSuccessHandler"
class="org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler"
p:defaultTargetUrl="/index/" />
<bean id="customAuthenticationFailureHandler"
class="org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler"
p:defaultFailureUrl="/login/error/" />
<bean id="rememberMeServices"
class="org.springframework.security.web.authentication.rememberme.PersistentTokenBasedRememberMeServices"
p:tokenRepository-ref="jdbcTokenRepository"
p:userDetailsService-ref="hibernateUserService"
p:key="pokeristStore"
p:tokenValiditySeconds="1209600" />
<bean id="jdbcTokenRepository"
class="org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl"
p:dataSource-ref="dataSource"/>
<bean id="rememberMeAuthenticationProvider" class="org.springframework.security.authentication.RememberMeAuthenticationProvider"
p:key="pokeristStore" />
<bean id="rememberMeFilter"
class="org.springframework.security.web.authentication.rememberme.RememberMeAuthenticationFilter"
p:rememberMeServices-ref="rememberMeServices"
p:authenticationManager-ref="authenticationManager" />
<bean id="authenticationFilter" class="org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter"
p:sessionAuthenticationStrategy-ref="sas"
p:authenticationManager-ref="authenticationManager"
p:authenticationFailureHandler-ref="customAuthenticationFailureHandler"
p:rememberMeServices-ref="rememberMeServices"
p:authenticationSuccessHandler-ref="customAuthenticationSuccessHandler"/>
<bean id="sas" class="org.springframework.security.web.authentication.session.ConcurrentSessionControlStrategy"
p:maximumSessions="1">
<constructor-arg name="sessionRegistry" ref="sessionRegistry" />
</bean>
<bean id="concurrencyFilter"
class="org.springframework.security.web.session.ConcurrentSessionFilter"
p:sessionRegistry-ref="sessionRegistry" />
<bean id="sessionRegistry"
class="org.springframework.security.core.session.SessionRegistryImpl" />
<bean id="passwordEncoder"
class="org.springframework.security.authentication.encoding.ShaPasswordEncoder">
<constructor-arg value="256"/>
</bean>
<bean id="saltSource"
class="org.springframework.security.authentication.dao.ReflectionSaltSource">
<property name="userPropertyToUse" value="username"/>
</bean>
<bean id="hibernateUserService"
class="com.mysite.service.simple.SecurityUserDetailsService"/>
<s:authentication-manager alias="authenticationManager">
<s:authentication-provider user-service-ref="hibernateUserService">
<s:password-encoder ref="passwordEncoder">
<s:salt-source ref="saltSource"/>
</s:password-encoder>
</s:authentication-provider>
<s:authentication-provider ref="rememberMeAuthenticationProvider" />
How can I solve this problem?
One of the solutions found by me - is to set alwaysReauthenticate property to 'true' in FilterSecurityInterceptor bean, but it affects the performance of web-site.

You need a ConcurrentSessionControlStrategy, to populate the session registry. This is described in the session management section of the manual. Check out the configuration example in there if you want to use plain Spring beans. Note that you need to inject it into both the supply the same reference to both the UsernamePasswordAuthenticationFilter and the session-management namespace element.

If you want SessionRegistry to be populated Spring Security have to create a session, try adding create-session="always" to your <http> tag in Spring Security configuration file.

Related

Discrepancy in the user roles(authorities) in the access token obtained from grant_type=password and grant_type=refresh_token

I have a situation:
Step 1: Obtained access token (grant_type=password) (A1) and also a refresh token.(RT1)
Step 2: Accessed resource (R) using the token (A1) - Success
Step 3:Revoked user access role for Resource R.
Step 4: Obtained access token (grant_type=password) (A2) and also a refresh token.(RT2)
Step 5: Accessed resource (R) using the token (A2) - Failed
till here all fine.now comes the unexpected part.
Step 6: Obtained new access token (grant_type=refresh_token) using RT2. Unexpectedly using this access token i was able to access resource R.
During this whole flow none of the token was expired one.
I see two issues here:- User roles aren't getting updated for refresh token on grant_type=password and for grant_type=refresh_token. Although access token has changed (Step 4) but refresh token remains same RT1 == RT2. hence any further usage of RT gives access token with previous roles.
How do i tell spring (oauth2) to update user roles (for the newly created token's) while obtaining the access token using refresh token and also while updating RT with new roles (step4), to resolve this discrepancy.
Below is the Authorization server configuration:
<?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:oauth="http://www.springframework.org/schema/security/oauth2"
xmlns:security="http://www.springframework.org/schema/security"
xsi:schemaLocation="http://www.springframework.org/schema/security/oauth2 http://www.springframework.org/schema/security/spring-security-oauth2.xsd
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="daoAuthenticationProvider" class="org.springframework.security.authentication.dao.DaoAuthenticationProvider">
<property name="userDetailsService">
<bean class="com.dummy.mc.security.service.UserDetailsServiceImpl">
<property name="userRepository" ref="userRepository" />
<property name="grantedAuthorityRepository" ref="grantedAuthorityRepository" />
</bean>
</property>
<property name="passwordEncoder">
<bean class="com.dummy.mc.security.password.McpmPasswordEncoder">
<property name="encodeHashAsBase64" value="true" />
</bean>
</property>
<property name="saltSource">
<bean class="org.springframework.security.authentication.dao.ReflectionSaltSource">
<property name="userPropertyToUse" value="salt" />
</bean>
</property>
</bean>
<!--https://stackoverflow.com/questions/49761597/spring-oauth2-clientid-passed-in-as-username-for-password-grant-type-->
<bean id="tokenStore" class="org.springframework.security.oauth2.provider.token.store.JdbcTokenStore">
<constructor-arg ref="dataSource" />
</bean>
<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="clientDetailsService" />
<property name="reuseRefreshToken" value="false"/>
</bean>
<bean id="oauthAccessDeniedHandler"
class="org.springframework.security.oauth2.provider.error.OAuth2AccessDeniedHandler" />
<bean id="clientCredentialsTokenEndpointFilter"
class="org.springframework.security.oauth2.provider.client.ClientCredentialsTokenEndpointFilter">
<property name="authenticationManager" ref="clientDetailAuthenticationManager" />
</bean>
<!-- Authentication manager for client (not resource-owner) authentication required to
protect the token endpoint URL -->
<security:authentication-manager id="clientDetailAuthenticationManager">
<security:authentication-provider user-service-ref="clientDetailsUserService"/>
</security:authentication-manager>
<bean id="clientDetailsUserService" class="org.springframework.security.oauth2.provider.client.ClientDetailsUserDetailsService">
<constructor-arg ref="clientDetailsService"/>
</bean>
<bean id="clientAuthenticationEntryPoint"
class="org.springframework.security.oauth2.provider.error.OAuth2AuthenticationEntryPoint">
<property name="realmName" value="test/client" />
<property name="typeName" value="Basic" />
</bean>
<security:http pattern="/oauth/token" create-session="stateless" use-expressions="true" authentication-manager-ref="authenticationManager">
<security:intercept-url pattern="/oauth/token" access="isAuthenticated()" />
<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>
<authorization-server client-details-service-ref="clientDetailsService"
xmlns="http://www.springframework.org/schema/security/oauth2" token-services-ref="tokenServices" >
<authorization-code />
<implicit />
<refresh-token />
<client-credentials />
<password authentication-manager-ref="authenticationManager" />
</authorization-server>
<!-- <oauth:resource-server id="resourceFilter" token-services-ref="tokenServices" authentication-manager-ref="authenticationManager" />
-->
<security:authentication-manager id="authenticationManager">
<security:authentication-provider ref="daoAuthenticationProvider">
</security:authentication-provider>
</security:authentication-manager>
<oauth:client-details-service id="clientDetailsService">
<oauth:client client-id="core-api" secret="secret"
authorized-grant-types="password,client_credentials,refresh_token" scope="read"
resource-ids="api-core" access-token-validity="36000"
authorities="ROLE_CLIENT,ROLE_TRUSTED_CLIENT" />
</oauth:client-details-service>
</beans>
Resource Server Configuration:
<mvc:default-servlet-handler />
<mvc:annotation-driven/>
<security:global-method-security pre-post-annotations="enabled"/>
<!-- TODO: make an access denied view that tells me something useful -->
<security:http use-expressions="true" entry-point-ref="oauthAuthenticationEntryPoint">
<security:intercept-url pattern="/**" access="isFullyAuthenticated() and hasRole('api.core')" />
<security:custom-filter ref="resourceServerFilter" before="PRE_AUTH_FILTER" />
<security:access-denied-handler ref="oauthAccessDeniedHandler" />
<security:anonymous />
</security:http>
<!-- It's just a "feature" of the Spring Security that an authentication manager is mandatory.
so install an empty one because it isn't used at run time -->
<security:authentication-manager/>
<oauth:resource-server id="resourceServerFilter" token-services-ref="tokenServices" resource-id="api-core"/>
<bean id="tokenServices" class="org.springframework.security.oauth2.provider.token.DefaultTokenServices" >
<property name="tokenStore" ref="tokenStore" />
</bean>
<bean id="tokenStore" class="org.springframework.security.oauth2.provider.token.store.JdbcTokenStore">
<constructor-arg ref="dataSource" />
</bean>
<bean id="oauthAuthenticationEntryPoint" class="org.springframework.security.oauth2.provider.error.OAuth2AuthenticationEntryPoint">
<property name="realmName" value="test/client" />
<property name="typeName" value="Basic" />
</bean>
<bean id="oauthAccessDeniedHandler" class="org.springframework.security.oauth2.provider.error.OAuth2AccessDeniedHandler" />
Authorities are loaded when access token its required.
Using jdbc store, authorities are saved to OAUTH_ACCESS_TOKEN table, AUTHENTICATION column.
When refresh token its required, authorities are loaded from database.
If authorities changed after access token was required, you will have to implement custom token store.
Take a look to org.springframework.security.oauth2.provider.token.store.JdbcTokenStore, and extend from it.

Spring Security and Okta

I've read several blogs about this subject and all the stackoverflow.com articles I can get my hands on, but nothing seems to answer the problem I've been encountering.
I've followed several Okta examples online, including the main blog post that was posted this year. I still run into the issue below, which when I trace through the spring-security code gets me to the voting process in spring and it fails.
TRACE 2017-08-22 16:45:11,128 [org.springframework.web.context.support.XmlWebApplicationContext] - Publishing event in Root WebApplicationContext: org.springframework.security.access.event.AuthorizationFailureEvent[source=FilterInvocation: URL: /SSO]
DEBUG 2017-08-22 16:45:11,129 [org.springframework.security.web.access.ExceptionTranslationFilter] - Access is denied (user is anonymous); redirecting to authentication entry point
org.springframework.security.access.AccessDeniedException: Access is denied
at org.springframework.security.access.vote.AffirmativeBased.decide(AffirmativeBased.java:83)
at org.springframework.security.access.intercept.AbstractSecurityInterceptor.beforeInvocation(AbstractSecurityInterceptor.java:206)
In my setup I'm not using spring boot or spring annotations, but rather good ol' spring xml configuration. I've look at the configuration enough that I don't see where the issue lies.
versions:
spring: 3.2.18.RELEASE
spring security: 3.2.7.RELEASE
spring saml2: 1.0.2.RELEASE
<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:security="http://www.springframework.org/schema/security"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd">
<!-- Enable auto-wiring
<context:annotation-config/>-->
<!-- Scan for auto-wiring classes in spring saml packages -->
<context:component-scan base-package="org.springframework.security.saml"/>
<!-- Unsecured pages -->
<security:http security="none" pattern="/favicon.ico"/>
<security:http security="none" pattern="/images/**"/>
<security:http security="none" pattern="/style/**"/>
<security:http security="none" pattern="/scripts/**"/>
<security:http security="none" pattern="/logout.jsp"/>
<!-- Security for the administration UI -->
<security:http pattern="/saml/web/**" use-expressions="false">
<security:access-denied-handler error-page="/saml/web/metadata/login"/>
<security:form-login login-processing-url="/saml/web/login" login-page="/saml/web/metadata/login" default-target-url="/saml/web/metadata"/>
<security:intercept-url pattern="/saml/web/metadata/login" access="IS_AUTHENTICATED_ANONYMOUSLY"/>
<security:intercept-url pattern="/saml/web/**" access="ROLE_ADMIN"/>
<security:custom-filter before="FIRST" ref="metadataGeneratorFilter"/>
</security:http>
<!-- Secured pages with SAML as entry point -->
<security:http entry-point-ref="samlEntryPoint" use-expressions="false">
<security:intercept-url pattern="/**" access="IS_AUTHENTICATED_FULLY"/>
<security:custom-filter before="FIRST" ref="metadataGeneratorFilter"/>
<security:custom-filter after="BASIC_AUTH_FILTER" ref="samlFilter"/>
</security:http>
<!-- Filters for processing of SAML messages -->
<bean id="samlFilter" class="org.springframework.security.web.FilterChainProxy">
<security:filter-chain-map request-matcher="ant">
<security:filter-chain pattern="/saml/login/**" filters="samlEntryPoint"/>
<security:filter-chain pattern="/saml/logout/**" filters="samlLogoutFilter"/>
<security:filter-chain pattern="/saml/metadata/**" filters="metadataDisplayFilter"/>
<security:filter-chain pattern="/saml/SSO/**" filters="samlWebSSOProcessingFilter"/>
<security:filter-chain pattern="/saml/SSOHoK/**" filters="samlWebSSOHoKProcessingFilter"/>
<security:filter-chain pattern="/saml/SingleLogout/**" filters="samlLogoutProcessingFilter"/>
<!-- <security:filter-chain pattern="/saml/discovery/**" filters="samlIDPDiscovery"/> -->
</security:filter-chain-map>
</bean>
<!-- Handler deciding where to redirect user after successful login -->
<bean id="successRedirectHandler"
class="org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler">
<property name="defaultTargetUrl" value="/app/buildingInformation"/>
</bean>
<!--
Use the following for interpreting RelayState coming from unsolicited response as redirect URL:
<bean id="successRedirectHandler" class="org.springframework.security.saml.SAMLRelayStateSuccessHandler">
<property name="defaultTargetUrl" value="/" />
</bean>-->
<!-- Handler deciding where to redirect user after failed login -->
<bean id="failureRedirectHandler"
class="org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler">
<property name="useForward" value="true"/>
<property name="defaultFailureUrl" value="/error.jsp"/>
</bean>
<!-- Handler for successful logout -->
<bean id="successLogoutHandler" class="org.springframework.security.web.authentication.logout.SimpleUrlLogoutSuccessHandler">
<property name="defaultTargetUrl" value="/logout.jsp"/>
</bean>
<!-- <bean id="mySecurityUserService" class="com.my.security.service.MySecurityUserService">
<property name="application" ref="application"/>
<property name="allowAllAccess" ref="allowAllAccess"/>
</bean> -->
<security:authentication-manager alias="authenticationManager">
<!-- Register authentication manager for SAML provider -->
<security:authentication-provider ref="samlAuthenticationProvider"/>
<!-- Register authentication manager for administration UI
<security:authentication-provider user-service-ref="mySecurityUserService"/>-->
</security:authentication-manager>
<!-- Logger for SAML messages and events -->
<bean id="samlLogger" class="org.springframework.security.saml.log.SAMLDefaultLogger"/>
<!-- Central storage of cryptographic keys -->
<bean id="keyManager" class="org.springframework.security.saml.key.JKSKeyManager">
<constructor-arg value="classpath:security/mykeystore.jks"/>
<constructor-arg type="java.lang.String" value="secret"/>
<constructor-arg>
<map>
<entry key="spring" value="secret"/>
</map>
</constructor-arg>
<constructor-arg type="java.lang.String" value="spring"/>
</bean>
<!-- Entry point to initialize authentication, default values taken from properties file -->
<bean id="samlEntryPoint" class="org.springframework.security.saml.SAMLEntryPoint">
<property name="defaultProfileOptions">
<bean class="org.springframework.security.saml.websso.WebSSOProfileOptions">
<property name="includeScoping" value="false"/>
</bean>
</property>
</bean>
<!-- IDP Discovery Service -->
<bean id="samlIDPDiscovery" class="org.springframework.security.saml.SAMLDiscovery">
<property name="idpSelectionPath" value="/WEB-INF/security/idpSelection.jsp"/>
</bean>
<!-- Filter automatically generates default SP metadata -->
<bean id="metadataGeneratorFilter" class="org.springframework.security.saml.metadata.MetadataGeneratorFilter">
<constructor-arg>
<bean class="org.springframework.security.saml.metadata.MetadataGenerator">
<property name="extendedMetadata">
<bean class="org.springframework.security.saml.metadata.ExtendedMetadata">
<!-- <property name="idpDiscoveryEnabled" value="true"/> -->
<property name="idpDiscoveryEnabled" value="false"/>
</bean>
</property>
</bean>
</constructor-arg>
</bean>
<!-- The filter is waiting for connections on URL suffixed with filterSuffix and presents SP metadata there -->
<bean id="metadataDisplayFilter" class="org.springframework.security.saml.metadata.MetadataDisplayFilter"/>
<!-- Configure HTTP Client to accept certificates from the keystore for HTTPS verification -->
<!--
<bean class="org.springframework.security.saml.trust.httpclient.TLSProtocolConfigurer">
<property name="sslHostnameVerification" value="default"/>
</bean>
-->
<!-- IDP Metadata configuration - paths to metadata of IDPs in circle of trust is here -->
<bean id="metadata" class="org.springframework.security.saml.metadata.CachingMetadataManager">
<constructor-arg>
<list>
<!-- Example of classpath metadata with Extended Metadata -->
<bean class="org.springframework.security.saml.metadata.ExtendedMetadataDelegate">
<constructor-arg>
<bean class="org.opensaml.saml2.metadata.provider.ResourceBackedMetadataProvider">
<constructor-arg>
<bean class="java.util.Timer"/>
</constructor-arg>
<constructor-arg>
<bean class="org.opensaml.util.resource.ClasspathResource">
<constructor-arg value="/metadata/idp.xml"/>
</bean>
</constructor-arg>
<property name="parserPool" ref="parserPool"/>
</bean>
</constructor-arg>
<constructor-arg>
<bean class="org.springframework.security.saml.metadata.ExtendedMetadata">
</bean>
</constructor-arg>
</bean>
<!-- Example of HTTP metadata without Extended Metadata -->
<!-- <bean class="org.opensaml.saml2.metadata.provider.HTTPMetadataProvider">
URL containing the metadata
<constructor-arg>
<value type="java.lang.String">https://dev-738438.oktapreview.com/app/exkbq3s0o4HnCFf3U0h7/sso/saml/metadata</value>
</constructor-arg>
Timeout for metadata loading in ms
<constructor-arg>
<value type="int">15000</value>
</constructor-arg>
<property name="parserPool" ref="parserPool"/>
</bean> -->
<!-- Example of file system metadata without Extended Metadata -->
<!--
<bean class="org.opensaml.saml2.metadata.provider.FilesystemMetadataProvider">
<constructor-arg>
<value type="java.io.File">/usr/local/metadata/idp.xml</value>
</constructor-arg>
<property name="parserPool" ref="parserPool"/>
</bean>
-->
</list>
</constructor-arg>
<!-- OPTIONAL used when one of the metadata files contains information about this service provider -->
<!-- <property name="hostedSPName" value=""/> -->
<!-- OPTIONAL property: can tell the system which IDP should be used for authenticating user by default. -->
<!-- <property name="defaultIDP" value="http://localhost:8080/opensso"/> -->
</bean>
<!-- SAML Authentication Provider responsible for validating of received SAML messages -->
<bean id="samlAuthenticationProvider" class="org.springframework.security.saml.SAMLAuthenticationProvider">
<!-- OPTIONAL property: can be used to store/load user data after login
<property name="userDetails" ref="mySecurityUserService"/> -->
</bean>
<!-- Provider of default SAML Context -->
<bean id="contextProvider" class="org.springframework.security.saml.context.SAMLContextProviderImpl"/>
<!-- Processing filter for WebSSO profile messages -->
<bean id="samlWebSSOProcessingFilter" class="org.springframework.security.saml.SAMLProcessingFilter">
<property name="authenticationManager" ref="authenticationManager"/>
<property name="authenticationSuccessHandler" ref="successRedirectHandler"/>
<property name="authenticationFailureHandler" ref="failureRedirectHandler"/>
</bean>
<!-- Processing filter for WebSSO Holder-of-Key profile -->
<bean id="samlWebSSOHoKProcessingFilter" class="org.springframework.security.saml.SAMLWebSSOHoKProcessingFilter">
<property name="authenticationManager" ref="authenticationManager"/>
<property name="authenticationSuccessHandler" ref="successRedirectHandler"/>
<property name="authenticationFailureHandler" ref="failureRedirectHandler"/>
</bean>
<!-- Logout handler terminating local session -->
<bean id="logoutHandler"
class="org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler">
<property name="invalidateHttpSession" value="false"/>
</bean>
<!-- Override default logout processing filter with the one processing SAML messages -->
<bean id="samlLogoutFilter" class="org.springframework.security.saml.SAMLLogoutFilter">
<constructor-arg index="0" ref="successLogoutHandler"/>
<constructor-arg index="1" ref="logoutHandler"/>
<constructor-arg index="2" ref="logoutHandler"/>
</bean>
<!-- Filter processing incoming logout messages -->
<!-- First argument determines URL user will be redirected to after successful global logout -->
<bean id="samlLogoutProcessingFilter" class="org.springframework.security.saml.SAMLLogoutProcessingFilter">
<constructor-arg index="0" ref="successLogoutHandler"/>
<constructor-arg index="1" ref="logoutHandler"/>
</bean>
<!-- Class loading incoming SAML messages from httpRequest stream -->
<bean id="processor" class="org.springframework.security.saml.processor.SAMLProcessorImpl">
<constructor-arg>
<list>
<ref bean="redirectBinding"/>
<ref bean="postBinding"/>
<ref bean="artifactBinding"/>
<ref bean="soapBinding"/>
<ref bean="paosBinding"/>
</list>
</constructor-arg>
</bean>
<!-- SAML 2.0 WebSSO Assertion Consumer -->
<bean id="webSSOprofileConsumer" class="org.springframework.security.saml.websso.WebSSOProfileConsumerImpl"/>
<!-- SAML 2.0 Holder-of-Key WebSSO Assertion Consumer -->
<bean id="hokWebSSOprofileConsumer" class="org.springframework.security.saml.websso.WebSSOProfileConsumerHoKImpl"/>
<!-- SAML 2.0 Web SSO profile -->
<bean id="webSSOprofile" class="org.springframework.security.saml.websso.WebSSOProfileImpl"/>
<!-- SAML 2.0 Holder-of-Key Web SSO profile -->
<bean id="hokWebSSOProfile" class="org.springframework.security.saml.websso.WebSSOProfileConsumerHoKImpl"/>
<!-- SAML 2.0 ECP profile -->
<bean id="ecpprofile" class="org.springframework.security.saml.websso.WebSSOProfileECPImpl"/>
<!-- SAML 2.0 Logout Profile -->
<bean id="logoutprofile" class="org.springframework.security.saml.websso.SingleLogoutProfileImpl"/>
<!-- Bindings, encoders and decoders used for creating and parsing messages -->
<bean id="postBinding" class="org.springframework.security.saml.processor.HTTPPostBinding">
<constructor-arg ref="parserPool"/>
<constructor-arg ref="velocityEngine"/>
</bean>
<bean id="redirectBinding" class="org.springframework.security.saml.processor.HTTPRedirectDeflateBinding">
<constructor-arg ref="parserPool"/>
</bean>
<bean id="artifactBinding" class="org.springframework.security.saml.processor.HTTPArtifactBinding">
<constructor-arg ref="parserPool"/>
<constructor-arg ref="velocityEngine"/>
<constructor-arg>
<bean class="org.springframework.security.saml.websso.ArtifactResolutionProfileImpl">
<constructor-arg>
<bean class="org.apache.commons.httpclient.HttpClient">
<constructor-arg>
<bean class="org.apache.commons.httpclient.MultiThreadedHttpConnectionManager"/>
</constructor-arg>
</bean>
</constructor-arg>
<property name="processor">
<bean class="org.springframework.security.saml.processor.SAMLProcessorImpl">
<constructor-arg ref="soapBinding"/>
</bean>
</property>
</bean>
</constructor-arg>
</bean>
<bean id="soapBinding" class="org.springframework.security.saml.processor.HTTPSOAP11Binding">
<constructor-arg ref="parserPool"/>
</bean>
<bean id="paosBinding" class="org.springframework.security.saml.processor.HTTPPAOS11Binding">
<constructor-arg ref="parserPool"/>
</bean>
<!-- Initialization of OpenSAML library-->
<bean class="org.springframework.security.saml.SAMLBootstrap"/>
<!-- Initialization of the velocity engine -->
<bean id="velocityEngine" class="org.springframework.security.saml.util.VelocityFactory" factory-method="getEngine"/>
<!--
XML parser pool needed for OpenSAML parsing
WARNING: If customizing a ParserPool implementation See https://shibboleth.net/community/advisories/secadv_20131213.txt
Specifically the following should be explicitly set to avoid exploits:
1) set pool property 'expandEntityReferences' to 'false'
2) set feature 'javax.xml.XMLConstants.FEATURE_SECURE_PROCESSING' to true
3) set feature 'http://apache.org/xml/features/disallow-doctype-decl' to true. This is a Xerces-specific feature,
including derivatives such as the internal JAXP implementations supplied with the Oracle and OpenJDK JREs. For
other JAXP implementations, consult the documentation for the implementation for guidance on how to achieve a
similar configuration.
-->
<bean id="parserPool" class="org.opensaml.xml.parse.StaticBasicParserPool" init-method="initialize"/>
<bean id="parserPoolHolder" class="org.springframework.security.saml.parser.ParserPoolHolder"/>
Thanks in advance for any help or for pointing me in the right direction.
This guide is a bit old, but it shows how to make things work with good ol' Spring XML: https://developer.okta.com/code/java/spring_security_saml.html

Spring Security Tonr2 remove application login

I was successfully able to add google as another authenticator in tonr2 example application. But what I'm stuck with is, removing the application's login screen and make use of google as mode of authentication into the application.
Also, each time I click on Google Info, I'm always taken to the "Accept"/"No Thanks" Page instead of remembering my approval already (I've logged in the same google account at all times)
Here is my modified spring-servlet.xml
<sec:http access-denied-page="/login.jsp?authorization_error=true" >
<sec:custom-filter ref="oauth2ClientFilter" after="EXCEPTION_TRANSLATION_FILTER" />
<sec:intercept-url pattern="/google/**" access="IS_AUTHENTICATED_ANONYMOUSLY" />
<sec:intercept-url pattern="/**" access="IS_AUTHENTICATED_ANONYMOUSLY" />
<sec:form-login authentication-failure-url="/login.jsp?authentication_error=true"
default-target-url="/index.jsp" login-page="/login.jsp"
login-processing-url="/login.do" />
<sec:logout logout-success-url="/index.jsp" logout-url="/logout.do" />
</sec:http>
<sec:authentication-manager >
<sec:authentication-provider>
<sec:user-service>
<sec:user name="marissa" password="wombat" authorities="ROLE_USER" />
<sec:user name="sam" password="kangaroo" authorities="ROLE_USER" />
</sec:user-service>
</sec:authentication-provider>
</sec:authentication-manager>
<!--apply the oauth client context -->
<oauth:client id="oauth2ClientFilter" />
<oauth:resource id="google" type="authorization_code"
client-id="174058367013-sdyu2a9q0fek0smsqgdjjtss26tp83dt.apps.googleusercontent.com"
client-secret="IBAAGEyTXmM0xijZ5AvvJ65x" authentication-scheme="query"
access-token-uri="https://accounts.google.com/o/oauth2/token"
user-authorization-uri="https://accounts.google.com/o/oauth2/auth"
client-authentication-scheme="form"
scope="https://www.googleapis.com/auth/userinfo.profile https://www.googleapis.com/auth/userinfo.email" />
<bean id="conversionService"
class="org.springframework.context.support.ConversionServiceFactoryBean">
<property name="converters">
<set>
<bean
class="org.springframework.security.oauth.examples.tonr.converter.AccessTokenRequestConverter" />
</set>
</property>
</bean>
<mvc:default-servlet-handler />
<mvc:annotation-driven>
<mvc:message-converters>
<bean
class="org.springframework.http.converter.BufferedImageHttpMessageConverter" />
</mvc:message-converters>
</mvc:annotation-driven>
<bean id="contentViewResolver"
class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
<property name="mediaTypes">
<map>
<entry key="json" value="application/json" />
</map>
</property>
<property name="defaultViews">
<bean
class="org.springframework.web.servlet.view.json.MappingJacksonJsonView" />
</property>
</bean>
<!--Basic application beans. -->
<bean id="viewResolver"
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/" />
<property name="suffix" value=".jsp" />
</bean>
<bean id="googleController"
class="org.springframework.security.oauth.examples.tonr.mvc.GoogleController">
<property name="googleRestTemplate">
<oauth:rest-template resource="google">
<property name="messageConverters">
<list>
<bean
class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter">
<property name="supportedMediaTypes">
<list>
<bean class="org.springframework.http.MediaType">
<!--google sends its json as text/javascript for some reason -->
<constructor-arg value="text" />
<constructor-arg value="javascript" />
</bean>
<bean class="org.springframework.http.MediaType">
<constructor-arg value="application" />
<constructor-arg value="json" />
</bean>
</list>
</property>
</bean>
</list>
</property>
</oauth:rest-template>
</property>
</bean>

Session management is not working in spring security

My Spring-security.xml:
<?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"
xmlns:p="http://www.springframework.org/schema/p"
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.xsd">
<!-- This is where we configure Spring-Security -->
<security:global-method-security pre-post-annotations="enabled" />
<!-- <security:global-method-security secured-annotations="enabled" /> -->
<security:http auto-config="false" use-expressions="true" access-denied-page="/access-deniad"
entry-point-ref="authenticationEntryPoint">
<security:intercept-url pattern="/RetailEnterpriseSuite/login.do" access="permitAll" requires-channel="https" />
<security:intercept-url pattern="/admin" access="hasRole('ROLE_ADMIN')" requires-channel="https"/>
<!-- <security:intercept-url pattern="/common" access="hasRole('ROLE_USER')"/> -->
<security:intercept-url pattern="/users" access="hasRole('ROLE_USER')"/>
<security:intercept-url pattern="/*" access="permitAll" requires-channel="any"/>
<security:logout
invalidate-session="true"
logout-success-url="/login.html"
logout-url=""/>
<!--
Querying the SessionRegistry for currently authenticated users and their sessions
http://static.springsource.org/spring-security/site/docs/3.1.x/reference/session-mgmt.html#list-authenticated-principals
-->
<security:custom-filter ref="authenticationFilter" position="FORM_LOGIN_FILTER"/>
<security:custom-filter ref="concurrencyFilter" position="CONCURRENT_SESSION_FILTER"/>
<security:custom-filter ref="singleEntryFilter" after="FORM_LOGIN_FILTER"/>
<security:session-management session-authentication-strategy-ref="sas"/>
</security:http>
<bean id="singleEntryFilter" class="com.stc.res.filter.SingleEntryFilter"
p:redirectURI="/login.html">
<property name="guardURI">
<list>
<!-- <value>/index.html</value> -->
<value>/index.html</value>
<!-- <value>/index.html</value>
<value>/index.html</value>
<value>/index.html</value>
<value>/index.html</value> -->
</list>
</property>
</bean>
<bean id="authenticationFilter" class="org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter"
p:sessionAuthenticationStrategy-ref="sas"
p:authenticationManager-ref="authenticationManager"
p:authenticationFailureHandler-ref="customAuthenticationFailureHandler"
p:authenticationSuccessHandler-ref="customAuthenticationSuccessHandler"/>
<!-- We just actually need to set the default failure url here -->
<bean id="customAuthenticationFailureHandler" class="org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler"
p:defaultFailureUrl="/loginfailed" />
<!-- We just actually need to set the default target url here -->
<bean id= "customAuthenticationSuccessHandler" class="org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler">
<property name="redirectStrategy" ref="customSuccessRedirStrategy" />
</bean>
<!-- <bean id="customAuthenticationSuccessHandler" class="org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler"
 p:redirectStrategy-ref="customSuccessRedirStrategy" /> -->
<bean id= "customSuccessRedirStrategy" class=" com.stc.res.customeredirection.CustomSuccessRedirection"> </bean>
<!-- The AuthenticationEntryPoint is responsible for redirecting the user to a particular page, like a login page,
whenever the server sends back a response requiring authentication -->
<!-- See Spring-Security Reference 5.4.1 for more info -->
<bean id="authenticationEntryPoint" class="org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint"
p:loginFormUrl="/login.html"/>
<!-- Declare an authentication-manager to use a custom userDetailsService -->
<!-- It's important to set the alias here because it's used by the authenticationFilter -->
<security:authentication-manager alias="authenticationManager">
<security:authentication-provider user-service-ref="userservice">
<security:password-encoder ref="passwordEncoder">
<security:salt-source ref="saltSource"/>
</security:password-encoder>
</security:authentication-provider>
<security:authentication-provider user-service-ref="jdbcUserService"/>
</security:authentication-manager>
<bean id="userservice" class="com.stc.res.service.UserLoginService" >
<property name="usrlogindao" ref="userLogindao"/>
</bean>
<bean id="userLogindao" class = "com.stc.res.dao.UserLoginDao" />
<bean id="jdbcUserService" class="com.stc.res.service.JdbcUserService">
<property name="customJdbcDao" ref="custjdbcDao"/>
</bean>
<bean id="custjdbcDao" class= "com.stc.res.dao.CustomJdbcDaoImpl">
<property name="dataSource" ref="dataSource"/>
</bean>
<bean id="jdbcAdminUserService" class="com.stc.res.controller.JdbcAdminUserService">
<property name="dataSource" ref="dataSource"/>
<property name="authenticationManager" ref="authenticationManager"/>
</bean>
<!-- Use a Sha encoder since the user's passwords are stored as Md5 in the database -->
<bean class="org.springframework.security.authentication.encoding.ShaPasswordEncoder" id="passwordEncoder"/>
<bean class="org.springframework.security.authentication.dao.ReflectionSaltSource" id="saltSource">
<property name="userPropertyToUse" value="username"/>
</bean>
<!-- <security:bean id="rememberMeServices" class="org.springframework.security.ui.rememberme.PersistentTokenBasedRememberMeServices">
<property name="tokenRepository" ref="jdbcTokenRepository" />
<property name="userDetailsService" ref="userservice" />
<property name="key" value="springRocks" />
<property name="alwaysRemember" value="false" />
</security:bean>
Uses a database table to maintain a set of persistent login data
<security:bean id="jdbcTokenRepository" class="org.springframework.security.ui.rememberme.JdbcTokenRepositoryImpl">
<property name="createTableOnStartup" value="false" />
<property name="dataSource" ref="dataSource" />
</security:bean>
-->
<!-- 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 -->
<!-- Filter required by concurrent session handling package
The ConcurrentSessionFilter requires two properties, sessionRegistry, which generally points to an
instance of SessionRegistryImpl, and expiredUrl, which points to the page to display when a session has expired.
See: http://static.springsource.org/spring-security/site/docs/3.1.x/reference/session-mgmt.html#list-authenticated-principals -->
<bean id="concurrencyFilter" class="org.springframework.security.web.session.ConcurrentSessionFilter"
p:sessionRegistry-ref="sessionRegistry"
p:expiredUrl="/login.html" />
<!-- Defines a concrete concurrent control strategy
Checks whether the user in question should be allowed to proceed, by comparing the number of
sessions they already have active with the configured maximumSessions value. The SessionRegistry
is used as the source of data on authenticated users and session data.
See: http://static.springsource.org/spring-security/site/docs/3.0.x/apidocs/org/springframework/security/web/authentication/session/ConcurrentSessionControlStrategy.html-->
<bean id="sas" class="org.springframework.security.web.authentication.session.ConcurrentSessionControlStrategy"
p:maximumSessions="1" error-if-maximum-exceeded="true" >
<constructor-arg name="sessionRegistry" ref="sessionRegistry" />
</bean>
<!-- Maintains a registry of SessionInformation instances
See: http://static.springsource.org/spring-security/site/docs/3.0.x/apidocs/org/springframework/security/core/session/SessionRegistry.html -->
<bean id="sessionRegistry" class="org.springframework.security.core.session.SessionRegistryImpl" />
</beans>
and I configured the in web.xml:
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
<dispatcher>REQUEST</dispatcher>
<dispatcher>ERROR</dispatcher>
</filter-mapping>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<filter>
<display-name>MycustomFilter</display-name>
<filter-name>MycustomFilter</filter-name>
<filter-class>com.stc.res.filter.MycustomFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>MycustomFilter</filter-name>
<url-pattern>/MycustomFilter</url-pattern>
</filter-mapping>
listener>
<listener-class>
org.springframework.security.web.session.HttpSessionEventPublisher
</listener-class>
</listener>
Please let me know where is the fault in this code, and please guide me. I am new to spring-security. Even user can login from different browser, without logging out.
Have you tried this snippet from the official documentation (preventing multiple logins):
<security:http ... >
....
<security:session-management>
<security:concurrency-control max-sessions="1" error-if-maximum-exceeded="true" />
</security:session-management>
</security:http>

Spring Security Configuration Leads to Perpetual Authentication Request

I have configured my web application with the following config file:
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:security="http://www.springframework.org/schema/security"
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.xsd
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.0.xsd">
<security:global-method-security secured-annotations="enabled" pre-post-annotations="enabled" />
<!--
Filter chain; this is referred to from the web.xml file. Each filter
is defined and configured as a bean later on.
-->
<!-- Note: anonumousProcessingFilter removed. -->
<bean id="filterChainProxy" class="org.springframework.security.web.FilterChainProxy">
<security:filter-chain-map path-type="ant">
<security:filter-chain pattern="/**"
filters="securityContextPersistenceFilter,
basicAuthenticationFilter,
exceptionTranslationFilter,
filterSecurityInterceptor" />
</security:filter-chain-map>
</bean>
<!--
This filter is responsible for session management, or rather the lack
thereof.
-->
<bean id="securityContextPersistenceFilter" class="org.springframework.security.web.context.SecurityContextPersistenceFilter">
<property name="securityContextRepository">
<bean class="org.springframework.security.web.context.HttpSessionSecurityContextRepository">
<property name="allowSessionCreation" value="false" />
</bean>
</property>
</bean>
<!-- Basic authentication filter. -->
<bean id="basicAuthenticationFilter" class="org.springframework.security.web.authentication.www.BasicAuthenticationFilter">
<property name="authenticationManager" ref="authenticationManager" />
<property name="authenticationEntryPoint" ref="authenticationEntryPoint" />
</bean>
<!-- Basic authentication entry point. -->
<bean id="authenticationEntryPoint" class="org.springframework.security.web.authentication.www.BasicAuthenticationEntryPoint">
<property name="realmName" value="Ayudo Web Service" />
</bean>
<!--
An anonymous authentication filter, which is chained after the normal authentication mechanisms and automatically adds an
AnonymousAuthenticationToken to the SecurityContextHolder if there is no existing Authentication held there.
-->
<!--
<bean id="anonymousProcessingFilter" class="org.springframework.security.web.authentication.AnonymousProcessingFilter">
<property name="key" value="ayudo" /> <property name="userAttribute" value="anonymousUser, ROLE_ANONYMOUS" /> </bean>
-->
<!--
Authentication manager that chains our main authentication provider
and anonymous authentication provider.
-->
<bean id="authenticationManager" class="org.springframework.security.authentication.ProviderManager">
<property name="providers">
<list>
<ref local="daoAuthenticationProvider" />
<ref local="inMemoryAuthenticationProvider" />
<!-- <ref local="anonymousAuthenticationProvider" /> -->
</list>
</property>
</bean>
<!--
Main authentication provider; in this case, memory implementation.
-->
<bean id="inMemoryAuthenticationProvider" class="org.springframework.security.authentication.dao.DaoAuthenticationProvider">
<property name="userDetailsService" ref="propertiesUserDetails" />
</bean>
<security:user-service id="propertiesUserDetails" properties="classpath:operators.properties" />
<!-- Main authentication provider. -->
<bean id="daoAuthenticationProvider" class="org.springframework.security.authentication.dao.DaoAuthenticationProvider">
<property name="userDetailsService" ref="userDetailsService" />
</bean>
<!--
An anonymous authentication provider which is chained into the ProviderManager so that AnonymousAuthenticationTokens are
accepted.
-->
<!--
<bean id="anonymousAuthenticationProvider" class="org.springframework.security.authentication.AnonymousAuthenticationProvider">
<property name="key" value="ayudo" /> </bean>
-->
<bean id="userDetailsService" class="org.springframework.security.core.userdetails.jdbc.JdbcDaoImpl">
<property name="dataSource" ref="dataSource" />
</bean>
<bean id="exceptionTranslationFilter" class="org.springframework.security.web.access.ExceptionTranslationFilter">
<property name="authenticationEntryPoint" ref="authenticationEntryPoint" />
<property name="accessDeniedHandler">
<bean class="org.springframework.security.web.access.AccessDeniedHandlerImpl" />
</property>
</bean>
<bean id="filterSecurityInterceptor" class="org.springframework.security.web.access.intercept.FilterSecurityInterceptor">
<property name="securityMetadataSource">
<security:filter-security-metadata-source use-expressions="true">
<security:intercept-url pattern="/*.html" access="permitAll" />
<security:intercept-url pattern="/version" access="permitAll" />
<security:intercept-url pattern="/users/activate" access="permitAll" />
<security:intercept-url pattern="/**" access="isAuthenticated()" />
</security:filter-security-metadata-source>
</property>
<property name="authenticationManager" ref="authenticationManager" />
<property name="accessDecisionManager" ref="accessDecisionManager" />
</bean>
<bean id="accessDecisionManager" class="org.springframework.security.access.vote.AffirmativeBased">
<property name="decisionVoters">
<list>
<bean class="org.springframework.security.access.vote.RoleVoter" />
<bean class="org.springframework.security.web.access.expression.WebExpressionVoter" />
</list>
</property>
</bean>
As soon as I run my application on tomcat, I get a request for username/password basic authentication dialog. Even when I try to access: localhost:8080/myapp/version, which is explicitly set to permitAll, I get the authentication request dialog. Help!
Thank,
Sammy
You have the basicAuthenticationFilter in your filter chain therefor it's going to try to authenticate a user. The permitAll will allow any user, but the request still needs to have a user in the SecurityContext (retrieved from your UserDetailsService).
If you want those URI's to allow all access (even without authenticating a user) then do this:
<intercept-url pattern="/version" filters="none"/>

Resources