I am trying to configure a filter to run for pre authentication to my web app using Ping Federate. I want this filter to be ran when all resources are being accessed, except for '/login'.
That is, every page should go through a filter except '/login'.
I am using Spring Security 3.2 and I understand that using
<security:http pattern="/login" auto-config="true" security="none">
is the new way to write
<intercept-url pattern="/login*" filters="none" />
However, when adding security='none' to my XML config file, the filter is still being picked up when I access localhost:8080/login.
Below is my XML configuration file:
<?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:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:security="http://www.springframework.org/schema/security"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.2.xsd">
<context:annotation-config />
<context:property-placeholder />
<security:global-method-security
pre-post-annotations="enabled" />
<bean id="resourceLoader" class="com.foo.bar.ResourceLoader">
<constructor-arg value="${PING_IDENTITY_CONFIG_FILE_NAME}" />
</bean>
<bean id="openTokenReader" class="com.foo.bar.OpenTokenReader" />
<security:http pattern="/login" use-expressions="true" security="none" />
<security:http use-expressions="true" auto-config="true"
entry-point-ref="http403EntryPoint">
<security:custom-filter position="PRE_AUTH_FILTER"
ref="openTokenFilter" />
<security:session-management
invalid-session-url="/login" />
<security:session-management>
<security:concurrency-control
max-sessions="1" error-if-maximum-exceeded="true" />
</security:session-management>
<security:logout />
</security:http>
<bean id="openTokenFilter"
class="com.foo.bar.OpenTokenRequestAuthenticationFilter">
<property name="authenticationManager" ref="authenticationManager" />
<property name="logoutURL" value="${PING_IDENTITY_LOGOUT_URL}" />
<property name="authenticationFailureHandler">
<bean
class="org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler">
<property name="defaultFailureUrl" value="/login" />
</bean>
</property>
</bean>
<bean id="preauthAuthProvider"
class="org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationProvider">
<property name="preAuthenticatedUserDetailsService">
<bean id="userDetailsServiceWrapper"
class="org.springframework.security.core.userdetails.UserDetailsByNameServiceWrapper">
<property name="userDetailsService" ref="customUserDetailsService" />
</bean>
</property>
</bean>
<security:authentication-manager alias="authenticationManager">
<security:authentication-provider
ref="preauthAuthProvider" />
</security:authentication-manager>
<bean id="customUserDetailsService" class="com.foo.bar.UserDetailsServiceImpl"></bean>
<bean id="http403EntryPoint"
class="org.springframework.security.web.authentication.Http403ForbiddenEntryPoint"></bean>
</beans>
I have tried nearly everything I can think of and for something that should be completely straightforward I have been unable to figure out the issue for quite some time.
Related
I have been working on jaas ldap authentication of an application. For the development purpose I am using tomcat to deploy the application. When I am deploying the application in tomcat , system is successfully authenticating the user by authenticating the user credentials against a ldap server and authorizing the user by fetching roles from database.
But my problem is when I deploying the application in web sphere server, I am encountering an exception
"unable to find LoginModule class: com.enterprise.security.ldap.TrivialLoginModule"
I have not included any trivial module in my application
But my application is running fine in tomcat.
For my authentication module following classes are defined:
CustomAuthenticationProvider.java
DummyRoleGranter.java
JaasLdapLogin.java
The configuration file is
ldap.jaas.config
Could someone please help me in identifying what I am missing for the Web Sphere Server.
My spring-security.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:security="http://www.springframework.org/schema/security"
xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:jdbc="http://www.springframework.org/schema/jdbc"
xsi:schemaLocation="http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-3.1.xsd
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.xsd">
<bean id="userDetailsService" class="com.work.application.service.UserDetailsService" />
<security:authentication-manager alias="authenticationmanager">
<security:authentication-provider ref="customauthProvider" />
</security:authentication-manager>
<security:http pattern="/resources/**" security="none" />
<security:http pattern="/login*" security="none" />
<security:http auto-config="true" use-expressions="true">
<security:intercept-url pattern="/**" access="isAuthenticated()" />
<security:form-login login-page="/login" authentication-failure-url="/loginfailed" default-target-url="/index"/>
<security:logout invalidate-session="true" delete-cookies="JSESSIONID" logout-success-url="/login" logout-url="/j_spring_security_logout"/>
<security:session-management session-fixation-protection="newSession">
<security:concurrency-control max-sessions="1" expired-url="/loginfailed" error-if-maximum-exceeded="false"/>
</security:session-management>
<security:csrf />
</security:http>
<bean id="csrfFilter" class="org.springframework.security.web.csrf.CsrfFilter">
<constructor-arg>
<bean
class="org.springframework.security.web.csrf.HttpSessionCsrfTokenRepository">
<property name="headerName" value="X-SECURITY" />
</bean>
</constructor-arg>
</bean>
<bean id="customauthProvider" class="com.work.application.authprovider.CustomAuthenticationProvider">
<constructor-arg name="delegate" ref="jaasAuthProvider" />
<property name="userDetailsService" ref="userDetailsService" />
</bean>
<bean id="jaasAuthProvider" class="org.springframework.security.authentication.jaas.JaasAuthenticationProvider">
<property name="loginConfig" value="classpath:ldap.jaas.config" />
<property name="authorityGranters">
<list>
<bean class="com.work.application.authprovider.DummyRoleGranter" />
</list>
</property>
<property name="loginContextName" value="LDAPLogin" />
<property name="callbackHandlers">
<list>
<bean class="org.springframework.security.authentication.jaas.JaasNameCallbackHandler" />
<bean class="org.springframework.security.authentication.jaas.JaasPasswordCallbackHandler" />
</list>
</property>
</bean>
<bean id="logoutFilter" class="org.springframework.security.web.authentication.logout.LogoutFilter">
<constructor-arg value="/login"/>
<constructor-arg>
<list>
<bean class="org.springframework.security.web.authentication.logout.CookieClearingLogoutHandler">
<constructor-arg>
<list>
<value>JSESSIONID</value>
</list>
</constructor-arg>
</bean>
<bean class="org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler"/>
</list>
</constructor-arg>
</bean>
</beans>
ldap.jaas.config
LDAPLogin
{
com.work.application.authprovider.JaasLdapLogin Sufficient
contextProvider="com.sun.jndi.ldap.LdapCtxFactory"
providerURL="ldap://aeiou:389/dc=app,dc=off,dc=net"
providerURL_2="ldap://aeiou3:389/dc=app,dc=off,dc=net"
providerURL_3="ldap://aeiou2:389/dc=app,dc=off,dc=net"
authenticationMode="simple"
providerURL_3="ldap://ABCDEFGH:389/"
providerURL_2="ldap://ABCDEFGI:389/"
principalPattern="cn={0},cn=Users,dc=app,dc=off,dc=net"
;
};
Got the work around. Since Websphere is not recognizing the config file so instead of using the JaasAuthenticationProvider I used DefaultJaasAuthenticationProvider and injected the configuration in the AppConfigurationEntry Map. It's working fine in websphere now.
How to enable logging in Spring Junit test? I think web.xml is not found when I do tests. Need to tell somehow to Junit where is web.xml with log configuration exists so logs will start working and I could bebug springs configuration errors.
My test class:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration("test-context.xml")
public class DSLCapacityTest {
private MockHttpServletRequest request;
private MockHttpServletResponse response;
#Autowired private DSLCapacity dc;
private AnnotationMethodHandlerAdapter adapter;
#Before
public void setUp() throws Exception {
request = new MockHttpServletRequest();
response = new MockHttpServletResponse();
response.setOutputStreamAccessAllowed(true);
adapter = new AnnotationMethodHandlerAdapter();
}
#Test
#Repeat(2)
public void testGetIndex() throws Exception {
request.setRequestURI("/dashboard/dsl-capacity/");
request.setMethod("GET");
ModelAndView mv = adapter.handle(request, response, dc);
assertSame("Incorrect message", "dashboard/dsl-capacity/index", mv.getViewName());
}
And my test-context.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:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:sec="http://www.springframework.org/schema/security"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:util="http://www.springframework.org/schema/util"
xmlns:jee="http://www.springframework.org/schema/jee"
xmlns:amq="http://activemq.apache.org/schema/core"
xmlns:jms="http://www.springframework.org/schema/jms"
xsi:schemaLocation="http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-4.2.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.1.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.2.xsd
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-4.2.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.2.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.1.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd
http://www.springframework.org/schema/jms http://www.springframework.org/schema/jms/spring-jms-4.2.xsd
http://activemq.apache.org/schema/core http://activemq.apache.org/schema/core/activemq-core-5.8.0.xsd">
<bean id="portalAuthenticator" class="uk.co.powergroup.portal.security.Authenticator">
</bean>
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"
p:ignoreUnresolvablePlaceholders="false">
<property name="location">
<value>file:/etc/portal-frontend/config.properties</value>
</property>
</bean>
<sec:authentication-manager>
<sec:authentication-provider ref='portalAuthenticator'/>
</sec:authentication-manager>
<sec:http pattern="/favicon.ico" security="none"/>
<sec:http pattern="/static/**" security="none"/>
<sec:http pattern="/logged-out" security="none"/>
<sec:http pattern="/login" security="none"/>
<sec:http pattern="/**/nologin*" security="none"/>
<sec:http auto-config="false" use-expressions="true">
<sec:csrf disabled="true"/>
<sec:intercept-url pattern="/forgot-password" access="isAnonymous()"/>
<sec:intercept-url pattern="/**" access="isAuthenticated()" />
<sec:logout logout-url="/logout" logout-success-url="/logged-out"/>
<sec:form-login login-page="/login" login-processing-url="/login-security-check" authentication-failure-url="/login" />
<sec:custom-filter position="CONCURRENT_SESSION_FILTER" ref="concurrencyFilter" />
<sec:session-management session-authentication-strategy-ref="sas"/>
<sec:custom-filter ref="userValidator" after="FILTER_SECURITY_INTERCEPTOR" />
</sec:http>
<sec:global-method-security pre-post-annotations="enabled" secured-annotations="enabled">
<sec:expression-handler ref="expressionHandler"/>
</sec:global-method-security>
<bean id="userValidator" class="uk.co.powergroup.portal.security.UserValidator">
</bean>
<bean id="expressionHandler" class="org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler">
<property name="permissionEvaluator" ref="myPermissionEvaluator"/>
</bean>
<bean id="myPermissionEvaluator" class="uk.co.powergroup.portal.security.PermissionChecker"/>
<bean id="concurrencyFilter" class="org.springframework.security.web.session.ConcurrentSessionFilter">
<constructor-arg name="sessionRegistry" ref="sessionRegistry" />
<constructor-arg name="expiredUrl" value="/login" />
</bean>
<bean id="sessionRegistry" class="org.springframework.security.core.session.SessionRegistryImpl"/>
<bean id="sas" class="org.springframework.security.web.authentication.session.ConcurrentSessionControlAuthenticationStrategy">
<constructor-arg name="sessionRegistry" ref="sessionRegistry" />
<property name="maximumSessions" value="-1"/>
</bean>
<bean id="myEmf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="persistenceUnitName" value="PORTAL2DB"/>
<property name="loadTimeWeaver">
<bean class="org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver"/>
</property>
</bean>
<bean id="txManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="myEmf"/>
</bean>
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://10.10.10.249:3306/portal"/>
<property name="username" value="portal"/>
<property name="password" value="twink13s"/>
</bean>
<bean id="jmsFactory" class="org.apache.activemq.pool.PooledConnectionFactory"
destroy-method="stop">
<property name="connectionFactory">
<bean class="org.apache.activemq.spring.ActiveMQConnectionFactory">
<property name="brokerURL">
<value>${activemq.uri}</value>
</property>
<property name="password">
<value>${activemq.password}</value>
</property>
<property name="userName">
<value>${activemq.user}</value>
</property>
</bean>
</property>
<!-- Make this 2.5 minutes in case for some reason the JMS tester job stops (sends every minute so default of 30 seconds too short) -->
<property name="idleTimeout" value="150000"/>
</bean>
<!-- Spring JMS Template -->
<bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate">
<property name="connectionFactory" ref="jmsFactory"/>
<property name="receiveTimeout" value="1000"/>
<property name="sessionTransacted" value="false"/>
</bean>
<bean id="jmsMessageListener" class="uk.co.powergroup.portal.jms.ReplyHandler"/>
<jms:listener-container container-type="default" connection-factory="jmsFactory" acknowledge="auto"
concurrency="2-5">
<jms:listener destination="${activemq.replyQueue}" ref="jmsMessageListener"/>
</jms:listener-container>
<bean id="threadPool" class="uk.co.powergroup.portal.helper.ThreadPool"/>
<bean name="retryTransactionsFilterBean" class="uk.co.powergroup.portal.helper.RetryFilter"/>
<bean id="conversionService"
class="org.springframework.context.support.ConversionServiceFactoryBean">
<property name="converters">
<set>
<bean class="uk.co.powergroup.portal.converters.PermissionConverter"/>
<bean class="uk.co.powergroup.portal.converters.RoleConverter"/>
<bean class="uk.co.powergroup.portal.converters.SuiteConverter"/>
<bean class="uk.co.powergroup.portal.converters.DataCentreConverter"/>
<bean class="uk.co.powergroup.portal.converters.DataCentreLocationConverter"/>
<bean class="uk.co.powergroup.portal.converters.CompanyConverter"/>
<bean class="uk.co.powergroup.portal.converters.HardwareConverter"/>
<bean class="uk.co.powergroup.portal.converters.RackConverter"/>
<bean class="uk.co.powergroup.portal.converters.EquipmentConverter"/>
<bean class="uk.co.powergroup.portal.converters.PowerDistributionUnitTypeConverter"/>
<bean class="uk.co.powergroup.portal.converters.TimeZoneDOConverter"/>
<bean class="uk.co.powergroup.portal.converters.DslLnsBearerTypeConverter"/>
<bean class="uk.co.powergroup.portal.converters.DslLnsLocationConverter"/>
<bean class="uk.co.powergroup.portal.converters.DslLnsOrganisationConverter"/>
<bean class="uk.co.powergroup.portal.converters.DslLnsConverter"/>
<bean class="uk.co.powergroup.portal.converters.BigDecimalConverter"/>
<bean class="uk.co.powergroup.portal.converters.PstnNumberDDIConverter"/>
</set>
</property>
</bean>
<context:component-scan base-package="uk.co.powergroup.portal.dao.impl"
name-generator="uk.co.powergroup.portal.misc.BeanNameGeneratorImpl"/>
You can do configuration for log4j.properties in your test case file so it will create log for you.
#BeforeClass
public static void init() {
PropertyConfigurator.configure("src/configuration/log4j.properties");
}
Java web containers mainly used web.xml file and also web.xml file not belongs to Spring context configuration.
I'm working on a Spring project which involves logging in with credentials stored in the database. Now that seems to work just fine, the only thing is, whenever I go to the page to log in, it automatically fills in "jimi" as the username and some password without me even having typed in anything.
This is my xml configuration:
spring-security.xml
<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.2.xsd">
<!-- enable use-expressions -->
<http auto-config="true" use-expressions="true">
<headers>
<cache-control />
</headers>
<intercept-url pattern="/admin**" access="hasRole('ROLE_ADMIN')" />
<form-login login-page="/user/login"
default-target-url="/home"
authentication-failure-url="/login?error"
username-parameter="username"
password-parameter="password"
login-processing-url="/auth/login_check" />
<logout logout-success-url="/login?logout" delete-cookies="JSESSIONID" />
</http>
<!-- Select users and user_roles from database -->
<authentication-manager>
<authentication-provider>
<jdbc-user-service data-source-ref="dataSource"
users-by-username-query=
"select email,password, enabled from user where email=?"
authorities-by-username-query=
"select email, role from user_roles where email =? " />
</authentication-provider>
</authentication-manager>
<beans:bean id="encoder" class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder">
</beans:bean>
</beans:beans>
spring-database.xml
<beans xmlns="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">
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://connectionurl" />
<property name="username" value="user" />
<property name="password" value="pass" />
</bean>
</beans>
mvc-dispatcher-servlet.xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">
<import resource="spring-database.xml"/>
<import resource="spring-security.xml"/>
<bean id="viewResolver"
class="org.springframework.web.servlet.view.InternalResourceViewResolver"
p:prefix="/WEB-INF/jsp/"
p:suffix=".jsp" />
<bean id="jpaDialect" class="org.springframework.orm.jpa.vendor.HibernateJpaDialect"/>
<bean id="emf"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="persistenceUnitName" value="medicapp" />
<property name="dataSource" ref="dataSource" />
<property name="persistenceProvider">
<bean class="org.hibernate.jpa.HibernatePersistenceProvider" />
</property>
</bean>
<bean id="tm" class="org.springframework.orm.jpa.JpaTransactionManager" p:entityManagerFactory-ref="emf" p:jpaDialect-ref="jpaDialect"/>
<tx:annotation-driven transaction-manager="tm"/>
<context:component-scan base-package="medicapp.*" />
<context:spring-configured />
<context:annotation-config />
<mvc:resources mapping="/resources/**" location="/resources/mytheme/" />
<mvc:annotation-driven/>
</beans>
Now for the issue with the hashing. As you can see, I have a BCrypt encoder bean declared in my spring-security.xml . However, when I try to use it, I can never log in. I can log in without it, however. I hashed a password using this password generator:
PasswordGenerator.java
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
public class PasswordEncoderGenerator {
public static void main(String[] args) {
String password = "123456";
BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
String hashedPassword = passwordEncoder.encode(password);
System.out.println(hashedPassword);
}
}
I copy/paste the output from there in my database, but no luck
Any help is appreciated.
Kind regards!
What you did in the spring-security.xml is declare the password encoder as a bean but you have not told the spring security to use the password encoder to use it for encoding the passwords.
What might be happening here would be, your password is not getting encoded before it is checked in the database thus your authentication fails.
Try this
<authentication-manager>
<authentication-provider>
<password-encoder ref="encoder" />
</authentication-provider>
</authentication-manager>
Adding the this will tell the spring security to encode the password using this bean and then check the database for the matching user object.
Hope it may help
We already have an OAuth2 authorization server set up, so I need to create a corresponding resource server (separate server). We plan to use the Spring Security OAuth2 project. Their documentation for setting up a resource server:
https://github.com/spring-projects/spring-security-oauth/wiki/oAuth2#resource-server-configuration
token-services-ref should point to the token-handling bean. However it seems like the token handling is done by the server itself even though it is the resource server. There doesn't seem to be any remote token services class or any configuration relating to a remote server. This is in contrast with the CloudFoundary UAA (https://github.com/cloudfoundry/uaa/blob/master/samples/api/src/main/webapp/WEB-INF/spring-servlet.xml) which has:
<bean id="tokenServices"
class="org.cloudfoundry.identity.uaa.oauth.RemoteTokenServices">
<property name="checkTokenEndpointUrl" value="${checkTokenEndpointUrl}" />
Is there any way to use Spring Security OAuth2 for a resource server that communicates with a separate OAuth2 Authorization server? How can I set the communication endpoint?
This is possible as long as the authorization server and resource server(s) access a shared tokenStore (e.g. using JdbcTokenStore with a common dataSource). You can just use DefaultTokenServices with a reference to your shared tokenStore. Below is an example Spring config which you should be able to tweak to fit your needs:
<?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:oauth2="http://www.springframework.org/schema/security/oauth2"
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-3.1.xsd
http://www.springframework.org/schema/security/oauth2
http://www.springframework.org/schema/security/spring-security-oauth2.xsd">
<bean id="tokenStore" class="org.springframework.security.oauth2.provider.token.JdbcTokenStore">
<constructor-arg name="dataSource" ref="dataSource" />
</bean>
<bean id="tokenServices" class="org.springframework.security.oauth2.provider.token.DefaultTokenServices">
<property name="tokenStore" ref="tokenStore" />
</bean>
<bean id="authenticationEntryPoint" class="org.springframework.security.oauth2.provider.error.OAuth2AuthenticationEntryPoint">
<property name="realmName" value="myRealm" />
</bean>
<bean id="oauthAccessDeniedHandler" class="org.springframework.security.oauth2.provider.error.OAuth2AccessDeniedHandler" />
<bean id="accessDecisionManager" class="org.springframework.security.access.vote.UnanimousBased">
<constructor-arg>
<list>
<bean class="org.springframework.security.oauth2.provider.vote.ScopeVoter" />
<bean class="org.springframework.security.access.vote.RoleVoter" />
<bean class="org.springframework.security.access.vote.AuthenticatedVoter" />
</list>
</constructor-arg>
</bean>
<!-- This is not actually used, but it's required by Spring Security -->
<security:authentication-manager alias="authenticationManager" />
<oauth2:expression-handler id="oauthExpressionHandler" />
<oauth2:web-expression-handler id="oauthWebExpressionHandler" />
<security:global-method-security pre-post-annotations="enabled" proxy-target-class="true">
<security:expression-handler ref="oauthExpressionHandler" />
</security:global-method-security>
<oauth2:resource-server id="myResource" resource-id="myResourceId" token-services-ref="tokenServices" />
<security:http pattern="/myPattern/**" create-session="never"
entry-point-ref="authenticationEntryPoint" access-decision-manager-ref="accessDecisionManager">
<security:anonymous enabled="false" />
<security:intercept-url pattern="/**" access="SCOPE_READ" method="GET" />
<security:intercept-url pattern="/**" access="SCOPE_READ" method="HEAD" />
<security:intercept-url pattern="/**" access="SCOPE_READ" method="OPTIONS" />
<security:intercept-url pattern="/**" access="SCOPE_WRITE" method="PUT" />
<security:intercept-url pattern="/**" access="SCOPE_WRITE" method="POST" />
<security:intercept-url pattern="/**" access="SCOPE_WRITE" method="DELETE" />
<security:custom-filter ref="myResource" before="PRE_AUTH_FILTER" />
<security:access-denied-handler ref="oauthAccessDeniedHandler" />
<security:expression-handler ref="oauthWebExpressionHandler" />
</security:http>
</beans>
Yes its possible. Like you have already mentioned in your question, RemoteTokenServices is the solution.
I have created one sample which has separate auth and resource server. Its just a sample to give a quick idea about the concept and open for extension.
Spring-AngularJS-OAuth2-Sample
I am adding Spring Security to one Spring project.
The architecture of the system is REST and user can access to different resources.
I would like to give access to personal information to administrators and users that are owners of this information.
I have started simple: filtering user profile like this:
In my service layer I wanted to use method annotations and include method parameters..
#PreAuthorize("hasRole('ROLE_ADMIN') or principal.userId == #id")
public Usuario getUser(int id) throws DAOException {
...
}
But this is not working at all. Any user can see all profiles (admins and all users also) when this URL is requested (Web layer):
#RequestMapping(value="/user/{uid}", method=RequestMethod.GET)
public ModelAndView getUser(#PathVariable int uid) throws DAOException {
userDAO = new UsuarioJPADAO();
userService.setUsuarioDAO(userDAO);
return new ModelAndView("user", "user", userService.getUser(uid));
}
Here is my security.xml
<?xml version="1.0" encoding="UTF-8"?>
<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.1.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-3.1.xsd">
<!-- Security Annotations -->
<global-method-security
pre-post-annotations="enabled"/>
<http auto-config="true" use-expressions="true">
<intercept-url pattern="/css/**" access="permitAll" />
<intercept-url pattern="/images/**" access="permitAll" />
<intercept-url pattern="/js/**" access="permitAll" />
<intercept-url pattern="/favicon.ico" access="permitAll" />
<intercept-url pattern="/login" access="permitAll" />
<intercept-url pattern="/users" access="hasRole('ROLE_ADMIN')" />
<intercept-url pattern="/users/page/*" access="hasRole('ROLE_ADMIN')" />
<intercept-url pattern="/customers" access="hasRole('ROLE_ADMIN')" />
<intercept-url pattern="/employees" access="hasRole('ROLE_ADMIN')" />
<intercept-url pattern="/search/*" access="hasRole('ROLE_ADMIN')" />
<intercept-url pattern="/*" access="hasAnyRole('ROLE_ADMIN, ROLE_EMPLOYEE, ROLE_PARTNER, ROLE_USER')" />
<intercept-url pattern="/*/*" access="hasAnyRole('ROLE_USER, ROLE_ADMIN')" />
<intercept-url pattern="/*/*/*" access="hasAnyRole('ROLE_USER, ROLE_ADMIN')" />
<intercept-url pattern="/*/*/*/*" access="hasAnyRole('ROLE_USER, ROLE_ADMIN')" />
<intercept-url pattern="/*/*/*/*/*" access="hasAnyRole('ROLE_USER, ROLE_ADMIN')" />
<intercept-url pattern="/*/*/*/*/*/*" access="hasAnyRole('ROLE_USER, ROLE_ADMIN')" />
<intercept-url pattern="/*/*/*/*/*/*/*" access="hasAnyRole('ROLE_USER, ROLE_ADMIN')" />
<form-login login-page="/login" login-processing-url="/doLogin"
authentication-failure-url="/login?error"
username-parameter="username" password-parameter="password"
default-target-url="/default" />
<logout invalidate-session="true" logout-success-url="/login?logout" logout-url="/logout"/>
</http>
<authentication-manager>
<authentication-provider user-service-ref="UsuarioService">
</authentication-provider>
</authentication-manager>
I have checked Spring Security 3.1 book and apparently my configuration is as book suggests. I have read other Stack Overflow posts (here and here) but I had no luck.
Update: Added application-context.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:p="http://www.springframework.org/schema/p"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:security="http://www.springframework.org/schema/security"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:jee="http://www.springframework.org/schema/jee"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.1.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.1.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.1.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.1.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-3.1.xsd">
<context:annotation-config />
<context:component-scan base-package="com.pe.fs" />
<mvc:annotation-driven />
<mvc:resources mapping="/**" location="/" />
<mvc:interceptors>
<bean class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor">
<property name="paramName" value="lang" />
</bean>
</mvc:interceptors>
<!-- DataSource -->
<bean id="jpaDataSource" class="oracle.jdbc.pool.OracleDataSource"
destroy-method="close"
p:driverType="oracle.jdbc.OracleDriver"
p:user="**********"
p:password="**********"
p:uRL="jdbc:oracle:thin:#localhost:1521:XE"
/>
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="persistenceXmlLocation" value="classpath*:META-INF/persistence.xml"></property>
<property name="persistenceUnitName" value="freesunPU" />
<property name="dataSource" ref="jpaDataSource" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.EclipseLinkJpaVendorAdapter">
<property name="showSql" value="false" />
</bean>
</property>
<property name="loadTimeWeaver">
<bean class="org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver"/>
</property>
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager"
p:entityManagerFactory-ref="entityManagerFactory" />
<tx:annotation-driven mode="aspectj"/>
<context:load-time-weaver aspectj-weaving="autodetect" />
Update: I have added spring-security-aspects to POM and no changes. Other changes suggested in answers have been tested with but annotations such #PreAuthorize are still not working. Cna this be a problem between contexts? Can be the usage of aspectJ the reason?
What am I doing wrong?
Finally I found solution.
In SO I found some usefull answers. See here and here.
I moved global-method-security to application-context.xml which is the context of my services.
<security:global-method-security
mode="aspectj"
secured-annotations="enabled"
jsr250-annotations="disabled"
pre-post-annotations="enabled"/>
Where mode="aspectj" as Javadoc says:
...can be used to specify that AspectJ should be used instead of the
default Spring AOP. If set, secured classes must be woven with the
AnnotationSecurityAspect from the spring-security-aspects module.
Of course, I have added to POM spring-security-aspects:
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-aspects</artifactId>
<version>3.1.3.RELEASE</version>
</dependency>
Add new interface:
public interface UserService extends UserDetailsService {
Usuario getUser(int id) throws DAOException
}
Implement it in your user service and try again. Spring will be able add requested authorization checks using JDK proxies.
As another option you can configure Spring to use some more heavyweight libraries like Javassist or even AspectJ.In this case interface will be not necessary.
EDIT. Make sure that global-method-security is declared in the same spring context with your user service bean.
The alternative way to make it work is to add the following code in your security.xml
<intercept-url pattern="/user/**" access="hasRole('ROLE_ADMIN')" />
It will ensure that only admin can access the resources starting with pattern /user/.