Permalink
Switch branches/tags
Find file Copy path
220 lines (188 sloc) 11.6 KB
<!--
Document : applicationContext-security.xml
Created on :
Author :
Copyright 2010 University of California at Berkeley
Description:
spring security namespace for CS service layer
ref: http://blog.springsource.com/2010/03/06/behind-the-spring-security-namespace/
-->
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:sec="http://www.springframework.org/schema/security"
xmlns:oauth="http://www.springframework.org/schema/security/oauth2"
xmlns:util="http://www.springframework.org/schema/util"
xmlns:context="http://www.springframework.org/schema/context"
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.xsd
http://www.springframework.org/schema/security/oauth2 http://www.springframework.org/schema/security/spring-security-oauth2.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<bean class="org.springframework.context.support.PropertySourcesPlaceholderConfigurer">
<!-- Read properties from security.properties file in the classpath. -->
<!-- Values in the file override the defaults set below. -->
<property name="ignoreResourceNotFound" value="true" />
<property name="locations" value="classpath:security.properties" />
<!-- Default property values. -->
<property name="properties">
<props>
<prop key="cors.allowed.origins"></prop>
</props>
</property>
</bean>
<!-- Convert string properties to complex types. -->
<bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean" />
<!-- Require client id and client secret via basic auth when granting tokens (https://tools.ietf.org/html/rfc6749#section-4.3.2).
Note that public (https://tools.ietf.org/html/rfc6749#section-2.1) clients, such as the CSpace web UI, may supply a
blank or publicly known "secret." The clientAuthenticationManager bean handles this client authentication. -->
<sec:http pattern="/oauth/token/**" create-session="stateless" authentication-manager-ref="clientAuthenticationManager">
<sec:intercept-url pattern="/oauth/token/**" access="isFullyAuthenticated()"/>
<sec:http-basic entry-point-ref="clientAuthenticationEntryPoint"/>
<sec:anonymous enabled="false"/>
<sec:csrf disabled="true"/>
<sec:access-denied-handler ref="oauthAccessDeniedHandler"/>
<!-- Handle CORS (preflight OPTIONS requests must be anonymous) -->
<sec:intercept-url method="OPTIONS" pattern="/oauth/token/**" access="isAnonymous()"/>
<sec:cors configuration-source-ref="corsSource" />
</sec:http>
<sec:http realm="org.collectionspace.services" create-session="stateless" authentication-manager-ref="userAuthenticationManager">
<!-- Exclude the resource path to public items' content from AuthN and AuthZ. Lets us publish resources with anonymous access. -->
<sec:intercept-url pattern="/publicitems/*/*/content" access="permitAll" />
<!-- Exclude the resource path to handle an account password reset request from AuthN and AuthZ. Lets us process password resets anonymous access. -->
<sec:intercept-url pattern="/accounts/requestpasswordreset" access="permitAll" />
<!-- Exclude the resource path to account process a password resets from AuthN and AuthZ. Lets us process password resets anonymous access. -->
<sec:intercept-url pattern="/accounts/processpasswordreset" access="permitAll" />
<!-- Exclude the resource path to request system info -->
<sec:intercept-url pattern="/systeminfo" access="permitAll" />
<!-- All other paths must be authenticated. -->
<sec:intercept-url pattern="/**" access="isFullyAuthenticated()" />
<sec:http-basic />
<sec:anonymous username="anonymous" />
<sec:csrf disabled="true" />
<!-- Handle CORS (preflight OPTIONS requests must be anonymous) -->
<sec:intercept-url method="OPTIONS" pattern="/**" access="isAnonymous()"/>
<sec:cors configuration-source-ref="corsSource" />
<!-- Insert the username from the security context into a request attribute for logging -->
<sec:custom-filter ref="userAttributeFilter" after="SECURITY_CONTEXT_FILTER" />
<!-- Handle token auth -->
<sec:custom-filter ref="oauthResourceServerFilter" before="PRE_AUTH_FILTER" />
</sec:http>
<sec:authentication-manager id="userAuthenticationManager">
<sec:authentication-provider ref="daoAuthenticationProvider"/>
</sec:authentication-manager>
<bean id="daoAuthenticationProvider" class="org.springframework.security.authentication.dao.DaoAuthenticationProvider">
<property name="userDetailsService" ref="userDetailsService" />
<property name="passwordEncoder">
<bean class="org.springframework.security.authentication.encoding.ShaPasswordEncoder">
<constructor-arg value="256"/>
<property name="encodeHashAsBase64" value="true" />
</bean>
</property>
</bean>
<bean id="userDetailsService" class="org.collectionspace.authentication.spring.CSpaceUserDetailsService">
<constructor-arg>
<bean class="org.collectionspace.authentication.realm.db.CSpaceDbRealm">
<constructor-arg>
<util:map>
<entry key="dsJndiName" value="CspaceDS" />
<entry key="principalsQuery" value="select passwd from users where username=?" />
<entry key="rolesQuery" value="select r.rolename from roles as r, accounts_roles as ar where ar.user_id=? and ar.role_id=r.csid" />
<entry key="tenantsQueryWithDisabled" value="select t.id, t.name from accounts_common as a, accounts_tenants as at, tenants as t where a.userid=? and a.csid = at.TENANTS_ACCOUNTS_COMMON_CSID and at.tenant_id = t.id order by t.id" />
<entry key="tenantsQueryNoDisabled" value="select t.id, t.name from accounts_common as a, accounts_tenants as at, tenants as t where a.userid=? and a.csid = at.TENANTS_ACCOUNTS_COMMON_CSID and at.tenant_id = t.id and NOT t.disabled order by t.id" />
<entry key="maxRetrySeconds" value="5000" />
<entry key="delayBetweenAttemptsMillis" value="200" />
</util:map>
</constructor-arg>
</bean>
</constructor-arg>
</bean>
<oauth:resource-server id="oauthResourceServerFilter" resource-id="cspace-services" token-services-ref="tokenServices" />
<sec:authentication-manager id="clientAuthenticationManager">
<sec:authentication-provider user-service-ref="clientDetailsUserDetailsService"/>
</sec:authentication-manager>
<bean id="clientDetailsUserDetailsService" class="org.springframework.security.oauth2.provider.client.ClientDetailsUserDetailsService">
<constructor-arg ref="clientDetails"/>
</bean>
<!-- The scope attribute below is a meaningless placeholder. In the future we may want to use it to limit
the permissions of particular clients. Currently a client has the full permissions of the user on
whose behalf it is acting. -->
<oauth:client-details-service id="clientDetails">
<oauth:client
client-id="cspace-ui"
resource-ids="cspace-services"
authorized-grant-types="password,refresh_token"
scope="full"
access-token-validity="3600"
refresh-token-validity="43200" />
</oauth:client-details-service>
<bean id="clientAuthenticationEntryPoint" class="org.springframework.security.oauth2.provider.error.OAuth2AuthenticationEntryPoint">
<property name="realmName" value="org.collectionspace.services/client"/>
<property name="typeName" value="Basic"/>
</bean>
<bean id="oauthAccessDeniedHandler" class="org.springframework.security.oauth2.provider.error.OAuth2AccessDeniedHandler"/>
<bean id="tokenServices" class="org.springframework.security.oauth2.provider.token.DefaultTokenServices">
<property name="tokenStore" ref="tokenStore" />
<property name="tokenEnhancer" ref="tokenEnhancer" />
<property name="supportRefreshToken" value="true" />
<property name="clientDetailsService" ref="clientDetails" />
</bean>
<bean id="tokenStore" class="org.springframework.security.oauth2.provider.token.store.JwtTokenStore">
<constructor-arg ref="tokenEnhancer" />
</bean>
<bean id="tokenEnhancer" class="org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter">
<!--
Can specify a signing key here. By default a random one is generated on bean instantiation,
which means that when CSpace is restarted, all granted tokens will become invalid. A
public/private key pair may also be supplied, using keyPair.
-->
<!-- <property name="signingKey" value="" /> -->
<property name="accessTokenConverter">
<bean class="org.springframework.security.oauth2.provider.token.DefaultAccessTokenConverter">
<property name="userTokenConverter">
<bean class="org.collectionspace.authentication.spring.CSpaceUserAuthenticationConverter">
<constructor-arg ref="userDetailsService" />
</bean>
</property>
</bean>
</property>
</bean>
<bean id="corsSource" class="org.springframework.web.cors.UrlBasedCorsConfigurationSource">
<property name="corsConfigurations">
<util:map>
<entry key="/**">
<bean class="org.springframework.web.cors.CorsConfiguration">
<property name="allowCredentials" value="true" />
<property name="allowedHeaders">
<list>
<value>Authorization</value>
<value>Content-Type</value>
</list>
</property>
<property name="allowedMethods">
<list>
<value>POST</value>
<value>GET</value>
<value>PUT</value>
<value>DELETE</value>
</list>
</property>
<property name="allowedOrigins" value="${cors.allowed.origins}" />
<property name="exposedHeaders">
<list>
<value>Location</value>
<value>Content-Disposition</value>
</list>
</property>
<property name="maxAge" value="86400" />
</bean>
</entry>
</util:map>
</property>
</bean>
<bean id="userAttributeFilter"
class="org.collectionspace.authentication.spring.CSpaceUserAttributeFilter">
</bean>
<!-- Switches on the AOP (AspectJ) load-time weaving -->
<context:load-time-weaver/>
</beans>