Wildfly 8 custom login module accessing HttpServletRequest params - wildfly-8

I am investigating the feasibility of using a wildfly custom login module.
The client will pass the mobile device id to the server as part of the login. I will check that the username and password are correct in the usual way then I need to check that the mobile device is approved to use the service.
The idea is that I will have a restful webservice method login that calls HttpServletRequest.login(u, p).
How do I get hold of the mobile device id inside the login module in the HttpServletRequest?
I could login and if that succeeds then test the device id in the webservice and if that is not approved, log the user out. But that seems rather messy.
What is the correct way of doing this?
EDIT
FEED BACK: I did it the way chris suggested. I implemented my own version of the CallBackHandler and an implementation of the Callback interface, inside the login method of my login module I do the following:
public boolean login() throws LoginException {
boolean login = super.login();
if (login) {
UuidCallback uuidCallback = new UuidCallback();
try {
super.callbackHandler.handle(new Callback[]{uuidCallback});
} catch (Exception e) {
LoginException le = new LoginException("Failed to get uuid");
le.initCause(e);
throw le;
}
System.out.print("Device UUID: "+uuidCallback.getUuid());
}
return login;
}
Inside the web service login method :
#Path("/login")
#Produces({ "application/json" })
public class LoginWebService {
#POST
public Response login(#Context HttpServletRequest request) throws LoginException {
CallbackHandler callbackHandler = new MyCallbackHandler(request.getParameter("username"), request.getParameter("password"), request.getParameter("uuid"));
Subject subject = new Subject();
LoginContext loginContext = new LoginContext("securityDomain", new subject, callbackHandler);
loginContext.login();
MyPrincipal principal = subject.getPrincipals(MyPrincipal.class).iterator().next();
}
}
You could also just set the uuid on the callback handler and then call getUUID() on the callback handler inside the LoginModule.login method. But I opted to go with the design even though it does not quite make sense to me.
I was still getting 403 when logged in and trying to access protected resources it turns out that if auth-constraint/role-name is *, you must supply at least one security-role.
<login-config>
<auth-method>FORM</auth-method>
<realm-name>mydomain</realm-name>
</login-config>
<security-constraint>
<web-resource-collection>
<web-resource-name>rest</web-resource-name>
<url-pattern>/rest/app/*</url-pattern>
</web-resource-collection>
<auth-constraint>
<role-name>*</role-name>
</auth-constraint>
</security-constraint>
<!-- after login there is a 403 on protected resources if no role and role-name * -->
<security-role>
<role-name>user</role-name>
</security-role>
All my users have a role user, which gives them access. I was able to get it working by excluding the security-role but then auth-constraint/role-name must be set to a literal role, in my case: "user"

I would suggesting creating a LoginContext and pass thru an implementation of a CallbackHandler. In the callbackhandler cater for the extra UUID property.
While this code works for me, you will need to update it to cater for the extra UUID property
public class NamePasswordCallbackHandler implements CallbackHandler {
private final String username;
private final String password;
private NamePasswordCallbackHandler(String username, String password) {
this.username = username;
this.password = password;
}
public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
for (Callback current : callbacks) {
if (current instanceof NameCallback) {
((NameCallback) current).setName(username);
} else if (current instanceof PasswordCallback) {
((PasswordCallback) current).setPassword(password.toCharArray());
} else {
throw new UnsupportedCallbackException(current);
}
}
}
}
I created my own implementation of the Configuration object (shown below as JBossJaasConfiguration).
Then pass thru this callbackhandler to your LoginContext:
CallbackHandler cbh = new NamePasswordCallbackHandler(username, password);
Configuration config = new JBossJaasConfiguration("mysqldomain");
LoginContext loginContext = new LoginContext("mycontext", new Subject(), cbh, config);
loginContext.login();
The property "mysqldomain" relates to the security-domain name in your standalone.xml
<subsystem xmlns="urn:jboss:domain:security:1.2">
<security-domains>
<security-domain name="mysqldomain" cache-type="default">
<authentication>
<login-module code="com.soccerx.security.DatabaseServerLoginRealm" flag="required">
<module-option name="dsJndiName" value="java:jboss/datasources/SoccerSoftwareDS"/>
<module-option name="principalsQuery" value="select userId, tenantId, password, salt from User where username=? and StatusId != 2"/>
<module-option name="rolesQuery" value="select Role, 'Roles' from User where Username=?"/>
<module-option name="password-stacking" value="useFirstPass"/>
<module-option name="principalClass" value="com.soccerx.security.DatabasePrincipal"/>
</login-module>
</authentication>
</security-domain>
<security-domains>
</subsystem>
While this is not a complete solution for your needs, I expect you can modify it to ensure that login fails should the UUID not match.
Note: You will need to cater for this in your CustomDatabaseLoginRealm, as defined in your standalone.xml. Meaning access the username/password/uuid and compare it to the values in the database.
More more documentation see here

Instead of calling HttpServletRequest.login() method directly from your restful webservice, you could configure a security-domain in Wildfly.
This security-domain should be referenced in your webapp web.xml file login-config element, with a security-constraint, to enable JAAS
Here is an example of web.xml file which declares a security-constraint and a login-config (with BASIC authentication method)
And a Wildfly standalone.xml configuration sample for security-domain configuration, using a standard provided Database login-module, not a custom one:
<security-domain name="securityDomain" cache-type="default">
<authentication>
<login-module code="Database" flag="required">
<module-option name="dsJndiName" value="java:/TestDS"/>
<module-option name="principalsQuery" value="select password from User where login = ? and (disabled is null or disabled = 0) and activated = 1"/>
<module-option name="rolesQuery" value="select name,'Roles' from Role r, User_Role ur, User u where u.login=? and u.id = ur.userId and r.id = ur.roleId"/>
<module-option name="hashAlgorithm" value="SHA-256"/>
<module-option name="hashEncoding" value="base64"/>
<module-option name="unauthenticatedIdentity" value="guest"/>
</login-module>
</authentication>
</security-domain>
Then, in your REST resource, you just have to use the #RolesAllowed or #PermitAll annotations to restrict access or not doing also authorization.

Related

Spring Security 4 issue using Query Method

I am using the latest spring security 4 version and it introduces a new feature to use the logged in user details directly in the query method using expression language. Here is my spring data repository code:
public interface UserRepository extends JpaRepository<User, Long> {
#Query("select username from User u where u.username = ?#{ principal?.username }")
User findByUsername(String username);
}
In the above code, I have an entity User as below:
#Entity
#Table(name = "users")
public class User {
#Id
#Column(name = "username", nullable = false, unique = true)
private String username;
#Column(name = "password", nullable = false)
#NotNull
private String password;
#Column(name = "enabled", nullable = false)
#NotNull
private Boolean enabled;
#Column(name = "role", nullable = false)
#Enumerated(EnumType.STRING)
private Role role;
//getters and setters
Also I have this entry for enabling this feature:
#Bean
public SecurityEvaluationContextExtension securityEvaluationContextExtension() {
return new SecurityEvaluationContextExtension();
}
When I run the application, I get the error:
Caused by: org.springframework.dao.InvalidDataAccessApiUsageException: Authentication object cannot be null; nested exception is java.lang.IllegalArgumentException: Authentication object cannot be null
at org.springframework.orm.jpa.EntityManagerFactoryUtils.convertJpaAccessExceptionIfPossible(EntityManagerFactoryUtils.java:381)
at org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.java:223)
at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.translateExceptionIfPossible(AbstractEntityManagerFactoryBean.java:417)
Caused by: java.lang.IllegalArgumentException: Authentication object cannot be null
at org.springframework.security.access.expression.SecurityExpressionRoot.<init>(SecurityExpressionRoot.java:46)
at org.springframework.security.data.repository.query.SecurityEvaluationContextExtension$1.<init>(SecurityEvaluationContextExtension.java:113)
at org.springframework.security.data.repository.query.SecurityEvaluationContextExtension.getRootObject(SecurityEvaluationContextExtension.java:113)
at org.springframework.data.repository.query.ExtensionAwareEvaluationContextProvider$EvaluationContextExtensionAdapter.<init>(ExtensionAwareEvaluationContextProvider.java:463)
at org.springframework.data.repository.query.ExtensionAwareEvaluationContextProvider.toAdapters(ExtensionAwareEvaluationContextProvider.java:210)
at org.springframework.data.repository.query.ExtensionAwareEvaluationContextProvider.access$000(ExtensionAwareEvaluationContextProvider.java:58)
What could be the issue. Here I am posting to check if there is any issue in using the query method. Can i use like principal.username, is that correct?
Update: When I removed the #Query from repository it works fine. That means its problem with the new spring security 4 using principal.username. Is there anything wrong in this expression?
#Query("select username from User u where u.username = ?#{ principal?.username }")
Pls try this custom class :-
class SecurityEvaluationContextExtension extends EvaluationContextExtensionSupport {
#Override
public String getExtensionId() {
return "Security";
}
#Override
public SecurityExpressionRoot getRootObject() {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
return new SecurityExpressionRoot(authentication){};
}
}
Not sure whether you have solved the issue in the meantime, but I noticed that your query should look like:
select u from User u where u.username = ?#{ principal }
assuming your principal object is the plain username String.
If you created your own SecurityEvaluationContextExtension class, and did not implement getAuthentication() method, you might be getting this exception.
In this link, you can see original SecurityEvaluationContextExtension.java file, that implements all necessary methods.
So, you don't need to implement this class on your own. Instead, you can add below dependency to your pom file to have the original one;
<!-- https://mvnrepository.com/artifact/org.springframework.security/spring-security-data -->
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-data</artifactId>
<version>4.2.1.RELEASE</version>
</dependency>
If you are using any other dependency manager rather than maven, you can goto related maven repo and get the definition that you want.
I hope this helps.

Authentication of SOAP messages

I have searched for a good example and cannopt find one. I want to take the username and password from the SOAP header, and set the spring security context after I authenticate using our exisiting service methods. I have implemented the Wss4jSecurityInterceptor and it validates the header element. WHat I need to do in the callback, or some other mechanism, is create an uthetication context so I can access it later in our endpoint.
However, I dont think that the callback is the correct place to do it, as I keep getting password supplied no password errors. I am new to spring security and integration.
Config:
<bean id="SOAPSecurityInterceptor" class="com.ps.snt.ws.interceptor.SOAPSecurityInterceptor">
<property name="validationActions" value="UsernameToken"/>
<property name="validationCallbackHandler" ref="callbackHandler"/>
</bean>
<bean id="callbackHandler" class="com.ps.snt.ws.interceptor.SOAPSecurityValidationCallbackHandler">
</bean>
callback:
public class SOAPSecurityValidationCallbackHandler extends SimplePasswordValidationCallbackHandler {
#Override
protected void handleUsernameToken(WSPasswordCallback callback) throws IOException, UnsupportedCallbackException {
System.out.println("In security callback " + callback.getPassword());
boolean valid = true;
String token = callback.getIdentifier();
String password = callback.getPassword();
Integer zoneID = null;
String username = null;
StringBuffer errorMessages = new StringBuffer();
if(StringUtils.isEmpty(token)) {
errorMessages.append("Username token cannot be empty");
valid = false;
} else {
Pattern pattern = Pattern.compile("^[\\w]+\\d\\d\\d\\d\\d");
Matcher matcher = pattern.matcher(token);
if(!matcher.matches()) {
valid = false;
errorMessages.append("Username token must be in the format 'user#zone'.");
}
else {
String[] parts = token.split("#");
username = parts[0];
zoneID = Integer.parseInt(parts[1]);
}
}
if(StringUtils.isEmpty(password)) {
errorMessages.append("Password cannot be empty.");
valid = false;
}
if(valid && username != null && zoneID != null) {
LoginService loginService = new LoginService();
LoginContextDO loginContextDO = loginService.getAuthenticatedLoginContext(username, password, zoneID);
AbstractAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(username, password);
authentication.setDetails(loginContextDO);
authentication.setAuthenticated(true);
SecurityContextHolder.getContext().setAuthentication(authentication);
} else {
System.out.println("Authetnication failed!");
}
}
}
My requirements are simple:
- validate the SOAP header (works)
- retrieve the username and password
- call our legacy service to create our login context
- set the spring security context (with logincontext as details) so I can use later in an endpoint
What mechanism can I use to validate the soap header and set a security context from that header?
SpringSecurityPasswordValidationCallbackHandler is for you. From Spring WS docs:
The SpringSecurityPasswordValidationCallbackHandler validates plain text and digest passwords using a Spring Security UserDetailService to operate. It uses this service to retrieve the (digest of ) the password of the user specified in the token. The (digest of) the password contained in this details object is then compared with the digest in the message. If they are equal, the user has successfully authenticated, and a UsernamePasswordAuthenticationToken is stored in theSecurityContextHolder. You can set the service using the userDetailsService. Additionally, you can set a userCache property, to cache loaded user details.
<beans>
<bean class="org.springframework.ws.soap.security.wss4j.callback.SpringDigestPasswordValidationCallbackHandler">
<property name="userDetailsService" ref="userDetailsService"/>
</bean>
<bean id="userDetailsService" class="com.mycompany.app.dao.UserDetailService" />
...
</beans>

How to set expire_in in OAUTH 2.0?

I am using OAuth 2.0 with spring for token generation and I want to set expire_in manually so token can expire as per my criteria. Any one help me?
This is my response:
{
access_token: "c7a6cb95-1506-40e7-87d1-ddef0a239f64"
token_type: "bearer"
expires_in: 43199
scope: "read"
}
It can be set with a ClientBuilder obtained from a ClientDetailsServiceConfigurer.
#Configuration
#EnableAuthorizationServer
public class OAuth2Config extends AuthorizationServerConfigurerAdapter {
#Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
.withClient("client")
.secret("secret")
.authorizedGrantTypes("authorization_code", "refresh_token", "password")
.scopes("app")
.accessTokenValiditySeconds(30);
}
// ... additional configuration
}
or directly on DefaultTokenServices depending on your need.
#Configuration
#EnableAuthorizationServer
public class OAuth2Config extends AuthorizationServerConfigurerAdapter {
#Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
// optionally here you could just get endpoints.getConsumerTokenService()
// and cast to DefaultTokenServices and just set values needed
DefaultTokenServices tokenServices = new DefaultTokenServices();
tokenServices.setTokenStore(endpoints.getTokenStore());
tokenServices.setSupportRefreshToken(true);
tokenServices.setClientDetailsService(endpoints.getClientDetailsService());
tokenServices.setTokenEnhancer(endpoints.getTokenEnhancer());
tokenServices.setAccessTokenValiditySeconds(60);
endpoints.tokenServices(tokenServices);
}
}
configure your oauth configuration changing your Bean TokenServices and setting accessTokenValiditySeconds property :
<bean id="tokenServices"
class="org.springframework.security.oauth2.provider.token.DefaultTokenServices">
<property name="accessTokenValiditySeconds" value="1" />
<property name="tokenStore" ref="tokenStore" />
<property name="supportRefreshToken" value="true" />
<property name="clientDetailsService" ref="clientDetails" />
</bean>
You can also configure the DefaultTokenServices in the application.yaml file.
security:
oauth2:
client:
clientId: client-id
clientSecret: client-secret
authorized-grant-types: authorization_code,refresh_token,password
scope: openid
access-token-validity-seconds: 30
Create a custom class of AuthorizationCodeAccessTokenProvider and override the parent
public method obtainAccessToken(OAuth2ProtectedResourceDetails details, AccessTokenRequest request)
In the overridden method of your custom class, call upon the program logic of its parent class:
DefaultOAuth2AccessToken token = super.obtainAccessToken(details, request);
This will return an AccessToken.
Now, you just have to manipulate the expired value of that token directly, by providing a timestamp from the past
token.setExpiresIn(int timestamp)
Also was searching for this answer and tried proposed solution from DeezCashews. But it didn't work for me, because there is a part of code which firstly check if this value is set in in column access_token_validity table oauth_client_details and only then greps value from tokenServices. So if your "expires_in" is set in oauth_client_details table, then you need to change it there.
Code which checks validity property in db :
protected int getAccessTokenValiditySeconds(OAuth2Request clientAuth) {
if (clientDetailsService != null) {
ClientDetails client = clientDetailsService.loadClientByClientId(clientAuth.getClientId());
Integer validity = client.getAccessTokenValiditySeconds();
if (validity != null) {
return validity;
}
}
return accessTokenValiditySeconds;
}
If you are using grails security oauth2 provider
you can only change grails-app/conf/spring/resources.groovy
import org.springframework.security.oauth2.provider.token.DefaultTokenServices
// Place your Spring DSL code here
beans = {
tokenServices(DefaultTokenServices){
accessTokenValiditySeconds = 600;
tokenStore = ref('tokenStore')
supportRefreshToken = true;
clientDetailsService = ref('clientDetailsService')
}
}
As such I don't think there is any policy to do that so. But there is one way which can lead to success.
Just use refresh_token API to make the current access_token invalid. :D
Simple is that.
public interface OAuth2AccessToken {
public static String BEARER_TYPE = "Bearer";
public static String OAUTH2_TYPE = "OAuth2";
/**
* The access token issued by the authorization server. This value is REQUIRED.
*/
public static String ACCESS_TOKEN = "access_token";
/**
* The type of the token issued as described in <a
* href="http://tools.ietf.org/html/draft-ietf-oauth-v2-22#section-7.1">Section 7.1</a>. Value is case insensitive.
* This value is REQUIRED.
*/
public static String TOKEN_TYPE = "token_type";
/**
* The lifetime in seconds of the access token. For example, the value "3600" denotes that the access token will
* expire in one hour from the time the response was generated. This value is OPTIONAL.
*/
public static String EXPIRES_IN = "expires_in";
/**
* The refresh token which can be used to obtain new access tokens using the same authorization grant as described
* in Section 6. This value is OPTIONAL.
*/
public static String REFRESH_TOKEN = "refresh_token";
/**
* The scope of the access token as described by <a
* href="http://tools.ietf.org/html/draft-ietf-oauth-v2-22#section-3.3">Section 3.3</a>
*/
public static String SCOPE = "scope";
/**
* The additionalInformation map is used by the token serializers to export any fields used by extensions of OAuth.
* #return a map from the field name in the serialized token to the value to be exported. The default serializers
* make use of Jackson's automatic JSON mapping for Java objects (for the Token Endpoint flows) or implicitly call
* .toString() on the "value" object (for the implicit flow) as part of the serialization process.
*/
Map<String, Object> getAdditionalInformation();
Set<String> getScope();
OAuth2RefreshToken getRefreshToken();
String getTokenType();
boolean isExpired();
Date getExpiration();
int getExpiresIn();
String getValue();
}

Spring Security + Vaadin: How to create custom non-JSP login form?

It's fairly easy to use custom JSP login page in Spring Security. Our application is based on Vaadin though and I don't want to have JSP login page. What I want is custom fancy login window created as Vaadin widget.
Well technically I can use Vaadin's FormLayout and name fields like j_username and j_password ... but this is Java class and not JSP file, so what do I specify in http Spring Security element? I mean:
<http auto-config='true'>
<intercept-url pattern="/**" access="ROLE_USER" />
<form-login login-page='MyLoginWindow.java or what?' />
</http>
I'm totally unfamiliar with Spring Security, but one of our guys at Vaadin made a demo application a couple of years ago https://github.com/peholmst/SpringSecurityDemo. I don't know if it's still up-to-date or if it even answers your question, but perhaps you could have a look and see for yourself if you can get any answers from there. Otherwise you could perhaps ping Petter personally and see if he has any fresh ideas about the topic.
Use LoginForm and in LoginListener use something like this
try {
val authentication = new UsernamePasswordAuthenticationToken(name, pass)
SecurityContextHolder.getContext.setAuthentication(authenticationManager.authenticate(authentication))
} catch {
case e: AuthenticationException => {
SecurityContextHolder.clearContext()
}
}
Please see below my approach. The code shows the functionality that occurs when clicking the login button.
loginBtn.addListener(new Button.ClickListener() {
#Override
public void buttonClick(ClickEvent event) {
// Getting the helper for working with spring context
// found here https://vaadin.com/wiki/-/wiki/Main/Spring%20Integration
SpringContextHelper helper = new SpringContextHelper(getApplication());
// Get the providerManagerBean
ProviderManager authenticationManager = (ProviderManager)helper
.getBean("authenticationManager");
// Get entered data for name and password
String name = usernameEntered;
String password = passwordEntered;
// Validation
if (StringUtils.isBlank(name) || StringUtils.isBlank(password)) {
getWindow().showNotification("Username or password cannot be empty",
Notification.TYPE_ERROR_MESSAGE);
} else {
try {
// Security functionality goes here
UsernamePasswordAuthenticationToken token =
new UsernamePasswordAuthenticationToken(name, password);
Authentication authentication = authenticationManager.authenticate(token);
// Set the authentication info to context
SecurityContextHolder.getContext().setAuthentication(authentication);
// During the authentification the AppUser instance was set as
// details, for more info about the user
AppUser user = (AppUser) authentication.getDetails();
if (user != null) {
// Switch the view after succesfull login
getApplication().getMainWindow().setContent(new ComboBoxUserStartsWith());
}
} catch (AuthenticationException e) {
// Display error occured during logining
getWindow().showNotification(e.getMessage(), Notification.TYPE_ERROR_MESSAGE);
}
}
}
});

Spring Security 2.0.x - Filter based on role type + Session based bean state

We have an application where users with proxy rights need to be able to see links in an application.
For example, we might have:
<s:intercept-url pattern="/resourceManager.htm" access=" ROLE_ADMIN_GROUP, ROLE_PROXY"/>
If the user has the role of proxy, but not the admin role, I need to present them with a page telling them that they need to be in proxy mode to see this page. Additionally, I need to check the permissions of the user they proxy to, to verify they have the correct role.
We have multiple pages, so I'd like to like to do this logic in a filter, so we can apply the logic across the board.
I'm mocking this up in pseudo code while I continue to research.
class Filter
{
protected void doFilterHttp()
{
//proxy summary is session based object
if(proxySummary.isProxyMode())
{
user = proxySummary.getProxiedUser()
//here load user's authorities
//will have to look at ldap authorities populator, but I should be able to work this part out
}
if(user.getGrantedAuthorities.contains("Role_Proxy"))
{
//Is there any way to tell possible valid roles for a url?
if(url.getPossibleRoles() intersect user.getGrantedAuthorities().size == 1 &&
intersection.contains(Role_Proxy))
{ redirectToProxyPage(); }
}
}
What's the best way to get any metadata for the url I'm attempting to access?
If there is no way to get information on all allowable roles for a url, then I imagine I would have to do it at the page.
Would upgrading to Spring Security 3 give me any more flexibility?
I ended up creating a runAsManager implementation that ran as the proxy user if in proxy mode. Otherwise, if the user only had a proxy role for the link, they were redirected. The runAsManager only modified the authentication object when in proxy mode.
I've included snippets of each class, so as not to make the post too long.
RunAsProxy Snippet
public Authentication buildRunAs(Authentication authentication, Object object,
ConfigAttributeDefinition config) {
//probably need to do something to cache the proxied user's roles
if(proxySummary.isProxyMode())
{
SpringSecurityLdapTemplate template = new SpringSecurityLdapTemplate(contextSource);
String dn = proxySummary.getLoggedInUser();
String [] tmp = { "uid", "cn" };
DirContextOperations user = template.retrieveEntry(dn, tmp);
GrantedAuthority[] proxiedAuthorities = authoritiesPopulator.getGrantedAuthorities(user, user.getStringAttribute("cn").toString());
return new RunAsUserToken(this.key, authentication.getPrincipal(), authentication.getCredentials(),
proxiedAuthorities, authentication.getClass());
}
return null;
}
Interceptor Code -> extends AbstractSecurityInterceptor implements Filter, Ordered
public void invoke(FilterInvocation fi) throws IOException, ServletException {
//same code as from proxy security interceptor here ...
//config attributes are the roles assigned to a link
ConfigAttributeDefinition cad = ((DefaultFilterInvocationDefinitionSource)objectDefinitionSource).lookupAttributes(fi.getRequestUrl());
if(cad != null)
{
HashSet<String> configAttributes = new HashSet<String>();
for(Object ca: cad.getConfigAttributes())
{
configAttributes.add(((ConfigAttribute)ca).getAttribute());
}
SecurityContext sc = SecurityContextHolder.getContext();
HashSet<String> authorities = new HashSet<String>();
for(GrantedAuthority ga: sc.getAuthentication().getAuthorities())
{
authorities.add(ga.getAuthority());
}
//intersection and remaining available roles to determine
//if they just have the proxy role
authorities.retainAll(configAttributes);
if(authorities.size() == 1 && authorities.contains("ROLE_PROXY"))
{
//redirect to page telling them to proxy
((HttpServletResponse)fi.getResponse()).sendRedirect("jsp/doProxy.jsp");
}
//System.out.println(cad);
fi.getRequest().setAttribute(FILTER_APPLIED, Boolean.TRUE);
//other boilderplate code
}
Spring Setup
<bean id="proxySecurityInterceptor" class="org.springframework.security.intercept.web.ProxySecurityInterceptor">
<property name="authenticationManager" ref="authenticationManager"/>
<property name="accessDecisionManager" ref="_accessManager"/>
<property name="proxySummary" ref="proxySummary" />
<property name="runAsManager" ref="runAsProxy" />
<property name="objectDefinitionSource">
<s:filter-invocation-definition-source>
<s:intercept-url pattern="/groupManager.htm*" access="ROLE_GLOBAL_ADMIN, ROLE_ADMIN_GROUP, ROLE_PROXY"/>
</s:filter-invocation-definition-source>
</property>
<s:custom-filter after="FILTER_SECURITY_INTERCEPTOR" />
</bean>

Resources