How to change spring security oauth2 default token endpoint? - spring-security-oauth2

We have spring security oauth2 based application. Every thing is working fine. But i am failed to change default token endpoint from "/oauth/token" to "/external/oauth/token".
My spring-servlet.xml
<http pattern="/external/oauth/token" create-session="stateless"
authentication-manager-ref="clientAuthenticationManager"
use-expressions="true" xmlns="http://www.springframework.org/schema/security">
<intercept-url pattern="/external/oauth/token" access="isFullyAuthenticated()" />
<anonymous enabled="false" />
<http-basic entry-point-ref="clientAuthenticationEntryPoint" />
<!-- include this only if you need to authenticate clients via request parameters -->
<custom-filter ref="clientCredentialsTokenEndpointFilter" after="BASIC_AUTH_FILTER" />
<access-denied-handler ref="oauthAccessDeniedHandler"/>
</http>
<oauth:authorization-server client-details-service-ref="clientDetails"
token-services-ref="tokenServices"
user-approval-handler-ref="userApprovalHandler" token-endpoint-url="/external/oauth/token">
<oauth:authorization-code />
<oauth:implicit />
<oauth:refresh-token />
<oauth:client-credentials />
<oauth:password />
</oauth:authorization-server>
But the result when i access this endpoint is
{
error: "unauthorized"
error_description: "An Authentication object was not found in the SecurityContext"
}
am i missing any thing ? Please suggest.

With the version 2.0.5.RELEASE or above of spring-security-oauth2
In one line in java based configuration, tested and works fine, somehow it's overriding the RequestMapping value of the TokenEndpoint class.
#Configuration
#EnableAuthorizationServer
protected static class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter {
#Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints
.pathMapping("/oauth/token", "<your custom endpoint>")
}
}

Just struggled with this for a few days, but have it working now on latest Spring Oauth2 1.0.5.RELEASE. I'm not 100% sure my solution is the classiest (Step 4 in particular), but it works and I'm able to move forward.
In my case, I wanted to remove the /oauth prefix from the urls to end up with just /token and /authorize. The solution for me was mostly xml config, with two hacks to override endpoint request mappings.
1 - In app context xml, add authorization-endpoint-url and token-endpoint-url attribs to your <oauth:authorization-server> element.
Mine:
<oauth:authorization-server client-details-service-ref="clientDetailsService" token-services-ref="tokenServices" user-approval-handler-ref="userApprovalHandler" authorization-endpoint-url="/authorize" token-endpoint-url="/token">
2 - In app context xml, adjust the security endpoints accordingly. There should be two, which respectively manage security on the token and auth urls. Need to update the pattern prop on <http> and <intercept-url> tags.
Mine:
<http pattern="/token/**" create-session="stateless" authentication-manager-ref="clientAuthenticationManager" xmlns="http://www.springframework.org/schema/security">
<intercept-url pattern="/token/**" access="IS_AUTHENTICATED_FULLY" />
...
<http pattern="/authorize/**" access-denied-page="/login.jsp?authorization_error=true" disable-url-rewriting="true" xmlns="http://www.springframework.org/schema/security">
<intercept-url pattern="/authorize/**" access="IS_AUTHENTICATED_FULLY" />
3 - (If you chose to employ the optional clientCreds filter.) In app context xml, you should already have wired-in the clientCredentialsTokenEndpointFilter bean as a <custom-filter> within yourelement. So, within the filter's bean, add afilterProcessesUrl` property.
Mine:
<bean id="clientCredentialsTokenEndpointFilter" class="org.springframework.security.oauth2.provider.client.ClientCredentialsTokenEndpointFilter">
<property name="authenticationManager" ref="clientAuthenticationManager" />
<property name="filterProcessesUrl" value="/token" />
</bean>
4 - The last step is to override the request mapping urls of the actual internal endpoint controllers. The spring oauth2 lib comes with two classes: AuthorizationEndpoint and TokenEndpoint. Each use #RequestMapping type annotations to bind the url (as we all do for our projects' app controllers). For me, it was a hair-pulling effort to attempt to override the value of the request mappings in any way other than to (sadly) recreate the spring class package in my src folder, copy the AuthorizationEndpoint and TokenEndpoint classes verbatim into said folder, and edit the inline #RequestMapping annotation values.
Anyway, that does the trick. Would love to hear of a more graceful way to override the endpoint controller request mapping values.
Thanks.
Final, working app context:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:sec="http://www.springframework.org/schema/security" xmlns:oauth="http://www.springframework.org/schema/security/oauth2"
xsi:schemaLocation="
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
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/security http://www.springframework.org/schema/security/spring-security-3.2.xsd
http://www.springframework.org/schema/security/oauth2 http://www.springframework.org/schema/security/spring-security-oauth2.xsd
"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
>
<!-- Declare OAuth2 services white-list. (This is the top of the config.) -->
<oauth:authorization-server client-details-service-ref="clientDetailsService" token-services-ref="tokenServices" user-approval-handler-ref="userApprovalHandler" authorization-endpoint-url="/authorize" token-endpoint-url="/token">
<oauth:authorization-code />
<oauth:implicit />
<oauth:refresh-token />
<oauth:client-credentials />
<!-- <oauth:password /> -->
</oauth:authorization-server>
<bean id="userApprovalHandler" class="org.springframework.security.oauth2.provider.approval.TokenServicesUserApprovalHandler">
<!-- This bean bridges client auth service and user tokens... kind of an out of place requirement. -->
<property name="tokenServices" ref="tokenServices" />
</bean>
<!-- This starts the far back-end config for client token management. -->
<sec:authentication-manager id="clientAuthenticationManager">
<sec:authentication-provider user-service-ref="clientDetailsUserService" />
</sec:authentication-manager>
<bean id="clientDetailsUserService" class="org.springframework.security.oauth2.provider.client.ClientDetailsUserDetailsService">
<constructor-arg ref="clientDetailsService" />
</bean>
<bean id="clientDetailsService" class="com.mycompany.oauth.spring.security.oauth2.IntegratedOauth2ClientDetailsService">
<!-- This bean is what wires OAuth2 into the persistence stack for client details stored in the oauth_client table. -->
</bean>
<!-- OAuth is layered on to spring security which is centered around users which requires a user auth manager. -->
<authentication-manager alias="authenticationManager" xmlns="http://www.springframework.org/schema/security">
<authentication-provider ref="daoAuthenticationProvider" />
</authentication-manager>
<bean id="daoAuthenticationProvider" class="org.springframework.security.authentication.dao.DaoAuthenticationProvider">
<property name="userDetailsService" ref="userDetailsService" />
</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" />
</bean>
<bean id="tokenStore" class="com.mycompany.oauth.spring.security.oauth2.IntegratedOAuth2TokenStore">
<!-- This bean is what wires OAuth2 tokens into my company's application stack. -->
<constructor-arg ref="dataSource" />
</bean>
<!-- **************************************************************************************** -->
<!-- Finally, sew OAuth into spring security with some http tags... -->
<!-- **************************************************************************************** -->
<!-- The OAuth2 endpoint for direct token requests (i.e. for client_credentials flow). -->
<http pattern="/token/**" create-session="stateless" authentication-manager-ref="clientAuthenticationManager" xmlns="http://www.springframework.org/schema/security">
<intercept-url pattern="/token/**" access="IS_AUTHENTICATED_FULLY" />
<anonymous enabled="false" />
<http-basic entry-point-ref="clientAuthenticationEntryPoint" />
<custom-filter ref="clientCredentialsTokenEndpointFilter" before="BASIC_AUTH_FILTER" />
<access-denied-handler ref="oauthAccessDeniedHandler" />
</http>
<bean id="clientCredentialsTokenEndpointFilter" class="org.springframework.security.oauth2.provider.client.ClientCredentialsTokenEndpointFilter">
<property name="authenticationManager" ref="clientAuthenticationManager" />
<property name="filterProcessesUrl" value="/token" />
</bean>
<bean id="clientAuthenticationEntryPoint" 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" />
<!-- The OAuth2 endpoint for user-approved authorization (i.e. for "authorization" flow involving user login/approve). -->
<http pattern="/authorize/**" access-denied-page="/login.jsp?authorization_error=true" disable-url-rewriting="true" xmlns="http://www.springframework.org/schema/security">
<intercept-url pattern="/authorize/**" access="IS_AUTHENTICATED_FULLY" />
<form-login authentication-failure-url="/login.jsp?authentication_error=true" default-target-url="http://www.mycompany.com/" login-page="/login.jsp" login-processing-url="/login.do" />
<http-basic />
<anonymous />
</http>
</beans>

For customize the token end point URL, do the following steps.
1) Write your own class that extends ClientCredentialsTokenEndpointFilter class & call ClientCredentialsTokenEndpointFilter class constructor with "/external/oauth/token" value.
super("/external/oauth/token");
2) Plug your new customize filter in security configuration.
Replace
<custom-filter ref="clientCredentialsTokenEndpointFilter" after="BASIC_AUTH_FILTER" />
with
<custom-filter ref="your customize filter" after="BASIC_AUTH_FILTER" />
3) Create your own class for new mapping (/external/oauth/token) & extend tokenendpoint.
4) Change http & intercept-url element's pattern attribute value to "/external/oauth/token"

You are making this harder than what it should be, it's actually very simple !
(Notice I'm using "oauth2:" instead of "oauth:" as the XML tag)
Go to your security-context.xml
Find "oauth2:authorization-server" in the above file.
<oauth2:authorization-server
client-details-service-ref="someService"
request-validator-ref="someScopeRequestValidator"
token-services-ref="someTokenServices" >
Just add token-endpoint-url="/oauth/whatever_you_like"
<oauth2:authorization-server
client-details-service-ref="someService"
request-validator-ref="someScopeRequestValidator"
token-services-ref="someTokenServices"
**token-endpoint-url="/oauth/whatever_you_like"** >

Related

Spring Security 4 - CredentialsExpiredException not redirecting to reset password - XML config

I am using Spring-Security 4 XML configuration to successfully implement password authentication in a spring-mvc webapp.
The problem I have is that when CredentialsExpiredException is thrown by DaoAuthenticationProvider, the system redirects to login-form, instead of reset password.
My context-security xml configuration is as follow:
<?xml version="1.0" encoding="UTF-8"?>
<b:beans xmlns="http://www.springframework.org/schema/security"
xmlns:b="http://www.springframework.org/schema/beans"
xmlns:p="http://www.springframework.org/schema/p"
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.xsd">
<b:bean id="authenticationEntryPoint" class="org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint">
<b:constructor-arg value="/index/form" />
</b:bean>
<http auto-config="true" use-expressions="true" disable-url-rewriting="true" entry-point-ref="authenticationEntryPoint" >
<intercept-url pattern="/" access="permitAll" requires-channel="https"/>
<intercept-url pattern="/index" access="permitAll" requires-channel="https"/>
<intercept-url pattern="/index/*" access="permitAll" requires-channel="https"/>
<intercept-url pattern="/**" access="hasAnyRole('USER','SYS_ADMIN' )" requires-channel="https"/>
<form-login
login-page="/index/form"
default-target-url="/dashboard"
login-processing-url="/index"
username-parameter="username"
password-parameter="password"
authentication-failure-handler-ref="exceptionTranslationFilter"
always-use-default-target="true"/>
<logout logout-url="/logout" logout-success-url="/index/logout"/>
<session-management>
<concurrency-control max-sessions="1" error-if-maximum-exceeded="true" />
</session-management>
</http>
<!-- password expiry functionality starts -->
<b:bean id="exceptionTranslationFilter" class="org.springframework.security.web.authentication.ExceptionMappingAuthenticationFailureHandler">
<b:property name="exceptionMappings">
<b:props>
<b:prop key="org.springframework.security.authentication.CredentialsExpiredException">/resetpassword</b:prop>
</b:props>
</b:property>
<b:property name="defaultFailureUrl" value="/index/error"/>
</b:bean>
<b:bean id="authenticationManager" class="org.springframework.security.authentication.ProviderManager">
<b:constructor-arg name="providers">
<b:list>
<b:ref bean="daoAuthenticationProvider"/>
</b:list>
</b:constructor-arg>
</b:bean>
<b:bean id="daoAuthenticationProvider" class="org.springframework.security.authentication.dao.DaoAuthenticationProvider ">
<b:property name="userDetailsService" ref="customUserDetailsService" />
<b:property name="passwordEncoder" ref="passwordEncoder" />
</b:bean>
<authentication-manager alias="authenticationManager">
<authentication-provider user-service-ref="customUserDetailsService" />
<authentication-provider ref="daoAuthenticationProvider" />
</authentication-manager>
<b:bean id="passwordEncoder" class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder" >
</b:bean>
Given the above configuration, when I enter correct username and password of user whose credentials have expired, I get redirected to url = "/index/form"
I have ran the debugger (I'm using Eclipse), and the code execution is as follows (all classes belong to Spring Security 4):
AbstractUserDetailsAuthenticationProvider.authenticate() throws CredentialsExpiredException when executing postAuthenticationChecks.check(user);
ExceptionMappingAuthenticationFailureHandler.onAuthenticationFailure() gets the url to be /resetpassword before calling getRedirectStrategy().sendRedirect(request, response, url);
DefaultRedirectStrategy.sendRedirect() gets the redirect url to be "/myapp/resetpassword"
The problem occurs on LoginUrlAuthenticationEntryPoint.commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException).
Because useForward is set to false, it calls redirectUrl = buildRedirectUrlToLoginPage(request, response, authException);
redirectUrl ends up being "/index/form".
Even if I set useForward to true and subclass LoginUrlAuthenticationEntryPoint in order to override determineUrlToUseForThisRequest the AuthenticationException I get is of type InsufficientAuthenticationException.
The interesting thing is that the url on my browser is https://localhost:8443/myapp/resetpassword, but what it displays is the login form.
Have you encountered this problem before? If so, how did you get spring to redirect to reset password?
Most of the configuration I obtained from https://stackoverflow.com/a/14383194/158499
Thanks in advance, Lucas
<intercept-url pattern="/**" access="hasAnyRole('USER','SYS_ADMIN' )" requires-channel="https"/>
when redirect to /resetpassword will redirect to login page. Please allow this url to access without authentication.
<intercept-url pattern="/resetpassword" access="permitAll" requires-channel="https"/>

Spring Security : convert XML to Annotation

I want to use the OpenID Connect client with Spring Java annotation.
Unfortunately, the sample Mitre ID Connect client is based on XML.
I managed to load XML by #ImportResource("classpath:servlet-context.xml")
but it would be much better to have pure Java annotation based solution.
I could not translate the following XML stuff into Spring Annotation:
<security:http auto-config="false" use-expressions="true"
disable-url-rewriting="true" entry-point-ref="authenticationEntryPoint"
pattern="/**">
<security:custom-filter before="PRE_AUTH_FILTER" ref="openIdConnectAuthenticationFilter" />
<security:logout />
</security:http>
<security:authentication-manager alias="authenticationManager">
<security:authentication-provider ref="openIdConnectAuthenticationProvider" />
</security:authentication-manager>
<bean id="authenticationEntryPoint" class="org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint">
<property name="loginFormUrl" value="http://localhost:10239/test" />
</bean>
<util:set id="namedAdmins" value-type="org.mitre.openid.connect.client.SubjectIssuerGrantedAuthority">
<bean class="org.mitre.openid.connect.client.SubjectIssuerGrantedAuthority">
<constructor-arg name="subject" value="XXX" />
<constructor-arg name="issuer" value="http://localhost:10239/test" />
</bean>
</util:set>
The bean xml tag is similar to the #bean annotation. See http://docs.spring.io/spring-javaconfig/docs/1.0.0.M4/reference/html/ch02s02.html
The util:set tag is similar to a method that returns a set of type org.mitre.openid.connect.client.SubjectIssuerGrantedAuthority. However this method has the #bean annotation as well.
For security related tags you can extend WebSecurityConfigurerAdapter
see https://www.mkyong.com/spring-security/spring-security-hello-world-annotation-example/

LDAP - AD Username Password configuration for context-source

I am using Spring Security to authenticate against Active Directory using LDAP protocol. Following code works well in authentication and setting up LDAP templates too (springSecurity.xml) :
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/security"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:ldap="http://www.springframework.org/schema/ldap"
xsi:schemaLocation="
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.1.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/ldap
http://www.springframework.org/schema/ldap/spring-ldap.xsd">
<http use-expressions="true">
<intercept-url pattern="/login" access="permitAll" />
<intercept-url pattern="/authenticated" access="isAuthenticated()" />
<form-login login-page="/login" default-target-url="/authenticated"
authentication-failure-url="/login?error=true" />
<logout />
</http>
<beans:bean
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<beans:property name="location">
<beans:value>classpath:/ldap.properties</beans:value>
</beans:property>
<beans:property name="SystemPropertiesMode">
<beans:value>2</beans:value> <!-- OVERRIDE is 2 -->
</beans:property>
</beans:bean>
<beans:bean id="adAuthenticationProvider"
class="org.springframework.security.ldap.authentication.ad.ActiveDirectoryLdapAuthenticationProvider">
<beans:constructor-arg value="${sample.ldap.domain}" />
<beans:constructor-arg value="${sample.ldap.url}" />
<beans:property name="useAuthenticationRequestCredentials"
value="true" />
<beans:property name="convertSubErrorCodesToExceptions"
value="true" />
</beans:bean>
<authentication-manager>
<authentication-provider ref="adAuthenticationProvider" />
</authentication-manager>
<!-- Ldap after authentication -->
<context:property-placeholder location="classpath:/ldap.properties"
system-properties-mode="OVERRIDE" />
<context:annotation-config />
<ldap:context-source id="contextSource"
password="${sample.ldap.password}"
url="${sample.ldap.url}"
username="${sample.ldap.userDn}"
base="${sample.ldap.base}"
referral="follow" />
<ldap:ldap-template id="ldapTemplate"
context-source-ref="contextSource" />
<ldap:repositories base-package="com.domain" />
<beans:bean class="com.service.UserService">
<beans:property name="directoryType" value="${sample.ldap.directory.type}" />
</beans:bean>
<!-- Required to make sure BaseLdapName is populated in UserService -->
<beans:bean
class="org.springframework.ldap.core.support.BaseLdapPathBeanPostProcessor" />
</beans:beans>
Authentication works fine while fetching j_username and j_password from login.jsp. To set up the ldap template i am using username and password attribute defined in properties file, but i wish to use same username and password from spring security. Please guide me as how to bind the Username and Password attribute properties in ldap:context-source id="contextSource" to spring security credentials.
The code is little messy, any input for improvement is welcomed.
As specified in the Configuration chapter of the reference documentation, you can use the Spring Security authentication for the ContextSource by specifying a custom authentication-source-ref in the the configuration element of the ContextSource. In your case you would use the a SpringSecurityAuthenticationSource, shipped with Spring Security.
<ldap:context-source id="contextSource"
url="${sample.ldap.url}"
base="${sample.ldap.base}"
referral="follow"
authentication-source-ref="authenticationSource"/>
<bean id="authenticationSource"
class="org.springframework.security.ldap.authentication.SpringSecurityAuthenticationSource" />

How to bypass form login filter if pre-authentication was successful in spring?

Is it possible to bypass the form login filter if the pre-authentication filter successfully extracted user information from the request? The form login filter would be used as a fallback in case the incoming request was not pre-authenticated.
I am working on a spring mvc application that has a standard login page with two custom filters and an authentication provider defined as follows:
<security:http>
<security:custom-filter position="FORM_LOGIN_FILTER" ref="loginFilter"/>
<security:custom-filter after="FORM_LOGIN_FILTER" ref="postAuthFilter"/>
</security:http>
<bean id="loginAuthProvider" class="com.auth.LoginAuthProvider" />
<security:authentication-manager alias="authManager">
<security:authentication-provider ref="loginAuthProvider" />
</security:authentication-manager>
I added a third filter and another provider to handle pre-authenticated requests:
<bean id="preAuthFilter" class="com.auth.PreAuthFilter" >
<property name="authenticationManager" ref="authManager" />
</bean>
<security:http>
<security:custom-filter position="PRE_AUTH_FILTER" ref="preAuthFilter"/>
<security:custom-filter position="FORM_LOGIN_FILTER" ref="loginFilter"/>
<security:custom-filter after="FORM_LOGIN_FILTER" ref="postAuthFilter"/>
</security:http>
<bean id="preAuthProvider" class="com.auth.PreAuthProvider" />
<bean id="loginAuthProvider" class="com.auth.LoginAuthProvider" />
<security:authentication-manager alias="authManager">
<security:authentication-provider ref="preAuthProvider" />
<security:authentication-provider ref="loginAuthProvider" />
</security:authentication-manager>
However, the login form filter is invoked even though the pre-authentication provider explicitly set the authenticated flag to true: auth.setAuthenticated(true);

How can <global-method-security> work on my controller by Spring-Security?

I'm stuck in this issue for a long time. I want to use #Secure to add Access Control to my controller ArticleController.java like this:
#RequestMapping(headers = "Accept=application/json")
#ResponseBody
#Secured("ROLE_ADMIN")
public ResponseEntity<String> listJson() {
HttpHeaders headers = new HttpHeaders();
headers.add("Content-Type", "application/json; charset=utf-8");
List<Article> result = Article.findAllArticles();
return new ResponseEntity<String>(Article.toJsonArray(result), headers, HttpStatus.OK);
}
listJson return a Json object for Articles but only Admin can read them. OK now I configure the Spring-Security to make this work.
I use security setup function of Spring-ROO, the following configures generated:
In web.xml:
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:META-INF/spring/applicationContext*.xml</param-value>
</context-param>
....
<servlet>
<servlet-name>BabyPortal</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>WEB-INF/spring/webmvc-config.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
In spring/webmvc-config.xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:security="http://www.springframework.org/schema/security"
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:xsi="http://www.w3.org/2001/XMLSchema-instance"
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.1.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-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/security http://www.springframework.org/schema/security/spring-security-3.1.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd">
<tx:annotation-driven/>
<!-- The controllers are autodetected POJOs labeled with the #Controller
annotation. -->
<context:component-scan base-package="com.tongxinyuan.babyportal"
use-default-filters="false">
<context:include-filter expression="org.springframework.stereotype.Controller"
type="annotation" />
</context:component-scan>
<!-- Turns on support for mapping requests to Spring MVC #Controller methods
Also registers default Formatters and Validators for use across all #Controllers -->
<mvc:annotation-driven conversion-service="applicationConversionService" />
<!-- Handles HTTP GET requests for /resources/** by efficiently serving
up static resources -->
<mvc:resources location="/, classpath:/META-INF/web-resources/"
mapping="/resources/**" />
<!-- Allows for mapping the DispatcherServlet to "/" by forwarding static
resource requests to the container's default Servlet -->
<mvc:default-servlet-handler />
<!-- Register "global" interceptor beans to apply to all registered HandlerMappings -->
<mvc:interceptors>
<bean class="org.springframework.web.servlet.theme.ThemeChangeInterceptor" />
<bean class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor"
p:paramName="lang" />
</mvc:interceptors>
<!-- Selects a static view for rendering without the need for an explicit
controller -->
<mvc:view-controller path="/login" />
<mvc:view-controller path="/" view-name="index" />
<mvc:view-controller path="/uncaughtException" />
<mvc:view-controller path="/resourceNotFound" />
<mvc:view-controller path="/dataAccessFailure" />
<!-- Resolves localized messages*.properties and application.properties
files in the application to allow for internationalization. The messages*.properties
files translate Roo generated messages which are part of the admin interface,
the application.properties resource bundle localizes all application specific
messages such as entity names and menu items. -->
<bean
class="org.springframework.context.support.ReloadableResourceBundleMessageSource"
id="messageSource" p:basenames="WEB-INF/i18n/messages,WEB-INF/i18n/application"
p:fallbackToSystemLocale="false" />
<!-- Store preferred language configuration in a cookie -->
<bean class="org.springframework.web.servlet.i18n.CookieLocaleResolver"
id="localeResolver" p:cookieName="locale" />
<!-- Resolves localized <theme_name>.properties files in the classpath to
allow for theme support -->
<bean
class="org.springframework.ui.context.support.ResourceBundleThemeSource"
id="themeSource" />
<!-- Store preferred theme configuration in a cookie -->
<bean class="org.springframework.web.servlet.theme.CookieThemeResolver"
id="themeResolver" p:cookieName="theme" p:defaultThemeName="standard" />
<!-- This bean resolves specific types of exceptions to corresponding logical
- view names for error views. The default behaviour of DispatcherServlet
- is to propagate all exceptions to the servlet container: this will happen
- here with all other types of exceptions. -->
<bean
class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver"
p:defaultErrorView="uncaughtException">
<property name="exceptionMappings">
<props>
<prop key=".DataAccessException">dataAccessFailure</prop>
<prop key=".NoSuchRequestHandlingMethodException">resourceNotFound</prop>
<prop key=".TypeMismatchException">resourceNotFound</prop>
<prop key=".MissingServletRequestParameterException">resourceNotFound</prop>
</props>
</property>
</bean>
<!-- Enable this for integration of file upload functionality -->
<bean
class="org.springframework.web.multipart.commons.CommonsMultipartResolver"
id="multipartResolver" />
<bean
class="com.tongxinyuan.babyportal.controller.ApplicationConversionServiceFactoryBean"
id="applicationConversionService" />
<bean class="org.springframework.web.servlet.view.UrlBasedViewResolver"
id="tilesViewResolver">
<property name="viewClass"
value="org.springframework.web.servlet.view.tiles2.TilesView" />
</bean>
<bean class="org.springframework.web.servlet.view.tiles2.TilesConfigurer"
id="tilesConfigurer">
<property name="definitions">
<list>
<value>/WEB-INF/layouts/layouts.xml</value>
<!-- Scan views directory for Tiles configurations -->
<value>/WEB-INF/views/**/views.xml</value>
</list>
</property>
</bean>
<security:global-method-security mode="aspectj" secured-annotations="enabled" pre-post-annotations="enabled"/>
</beans>
In /spring/applicationContext-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">
<!-- HTTP security configurations -->
<http auto-config="true" use-expressions="true">
<form-login login-processing-url="/resources/j_spring_security_check" login-page="/login" authentication-failure-url="/login?login_error=t" />
<logout logout-url="/resources/j_spring_security_logout" />
<!-- Configure these elements to secure URIs in your application -->
<intercept-url pattern="/choices/**" access="hasRole('ROLE_ADMIN')" />
<intercept-url pattern="/member/**" access="isAuthenticated()" />
<intercept-url pattern="/resources/**" access="permitAll" />
<intercept-url pattern="/*.html" access="hasRole('ROLE_ADMIN')" />
</http>
<!-- Configure Authentication mechanism -->
<authentication-manager alias="authenticationManager">
<authentication-provider>
<user-service>
<user name="admin" password="admin" authorities="ROLE_ADMIN" />
<user name="user" password="user" authorities="ROLE_USER" />
</user-service>
</authentication-provider>
</authentication-manager>
</beans:beans>
Firstly I tried adding the <global-method-security mode="aspectj" secured-annotations="enabled" pre-post-annotations="enabled"/> to /spring/applicationContext-security.xml but didn't work. Then maybe the the controller is not in the same context of security context, so I add the to /spring/webmvc-config.xml which started with DispatcherServlet, didn't work.
I also added to another default applicationContext.xml, it didn't work either. I don't know how to configure the <global-method-security> that can make the method security work. It seems I only use one context, did I miss something? Hope the information is enough to make this issue clear.
PS: The generated URL method works very well: <intercept-url pattern="/*.html" access="hasRole('ROLE_ADMIN')" />.
Added:
According to #LukeTaylor 's comments: I added the <global-method-security> to webmvc-config.xml and removed the mode="aspectj", it works, and I did some experiments, still have some questions:
1) It works but only for ArticleController.java, the #Secure tag in ArticleController_Roo_Controller.aj still don't work, is that something related to "waving"?
2) Can you explain to me why mode=aspectj make it mess here?
As suggested by #Luke Taylor in the comments the tag <sec:global-method-security/> needs to be defined in the dispatcher-servlet.xml(webmvc-config.xml in this case) file. And there is no need to have attribute mode="aspectj".
Thanks.

Resources