I need to redirect the user to 2 different logout urls based on his role. How do i go about doing this?
i am using spring security 2.0 and my xml looks something like this:
<s:http access-denied-page="/" >
<s:intercept-url pattern="/pages/SplashPage.jsf" access="IS_AUTHENTICATED_ANONYMOUSLY"/>
<s:intercept-url pattern="/pages/Home.jsf" access="ROLE_USER,ROLE_MERCHANT"/>
<s:anonymous/>
<s:form-login
login-page="/"
login-processing-url="/j_spring_security_check"
default-target-url="/pages/Home.jsf"
authentication-failure-url="/" always-use-default-target='false' />
<s:logout invalidate-session="true" logout-url="/pages/logout.jsf" logout-success-url="/" />
<s:concurrent-session-control max-sessions="1" exception-if-maximum-exceeded="false"/>
</s:http>
I couldnt find any right way to do this, so i ended up with a hack:
dont invalidate-session
change the logout-success-url to special redirect controller
in that controller, pull the user session to tell the user type
invalidate the session
redirect to proper url for the usertype
EDIT - updated to a Spring Security 2.0 solution.
Replace the LogoutFilter with your a subclass the overrides doFilterHttp:
public void doFilterHttp(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException,
ServletException {
if (requiresLogout(request, response)) {
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
if (logger.isDebugEnabled()) {
logger.debug("Logging out user '" + auth + "' and redirecting to logout page");
}
for (int i = 0; i < handlers.length; i++) {
handlers[i].logout(request, response, auth);
}
// Do role-specific logic here to determine targetUrl
sendRedirect(request, response, targetUrl);
return;
}
chain.doFilter(request, response);
}
Replace the LogoutFilter as follows:
<beans:bean id="myLogoutFilter" class="com.mycompany.MyLogoutFilter">
<custom-filter position="LOGOUT_FILTER"/>
</beans:bean>
Related
I try to implement sending message to a specific user via Spring WebSocket.
Method from controller
simpMessagingTemplate.convertAndSend("/user/" + username + "/queue/messages", messageDto);
But how to get username? As I searched for that need to add DefaultHandshakeHandler to websocket endpoint
I've added:
<websocket:message-broker application-destination-prefix="/app">
<websocket:stomp-endpoint path="/chat" allowed-origins="*">
<websocket:handshake-handler ref="customHandler"/>
<websocket:handshake-interceptors>
<bean class="org.springframework.web.socket.server.support.HttpSessionHandshakeInterceptor"/>
</websocket:handshake-interceptors>
<websocket:sockjs/>
</websocket:stomp-endpoint>
<websocket:simple-broker prefix="/topic, /queue" />
public class CustomDefaultHandshakeHandler extends DefaultHandshakeHandler {
#Override
protected Principal determineUser(ServerHttpRequest request, WebSocketHandler wsHandler, Map<String, Object> attributes) {
But attributes is null
.....
return principal;
}
}
For example here: Sending message to specific user using spring
String name = (String)attributes.get("name");
But attributes are empty(null).
What should I do to get username attribute?
frontend use Angular4 and stomp over WebSocket service
this.stomp.configure({
host: AppSettings.WEBSOCKET_HOST + '/chat',
headers: {'username': 'test'},
queue:{'init':false}
});
Lets say that you have websites http://simple.com and a lot of subdomain, for example: http://first.simple.com, http://second.simple.com, http://last.simple.com.
Lets say that a user goes to last.simple.com and they get authenticated through the normal ASP .NET membership provider.
Then, from that site, they get sent to (redirection, linked, whatever works) site http://last.simple.com, and the intent of site http://first.simple.com was to pass that user to the other site as the status of isAuthenticated, so that the site http://last.simple.com does not ask for the credentials of said user again.
This worked in Chrome, Mozila, Opera(last versions), Safari, but don't worked in IE(all versions) and Opera( < v12.01).
Scheme:
User, address(first.simple.com) -> post query to server, json answer,
if auth - redirect. May be problem in json(need use 'jsonp')?
web.config
<system.web>
<authentication mode="Forms">
<forms name=".ASPXAUTH" protection="All" domain=".simple.com" enableCrossAppRedirects="true" />
</authentication>
</system.web>
SessionService
public void Authenticate(string username)
{
FormsAuthentication.SetAuthCookie(username, false);
var cookie = FormsAuthentication.GetAuthCookie(username, false);
cookie.HttpOnly = true;
cookie.Path = "/";
cookie.Domain = domain;
this.context.Response.AppendCookie(cookie);
}
Global.asax
protected void Application_PreRequestHandlerExecute(Object sender, EventArgs e)
{
const string aspSessionid = "ASP.NET_SessionId";
if (Context.Handler is IRequiresSessionState || Context.Handler is IReadOnlySessionState)
{
var cookie = Context.Request.Cookies[aspSessionid];
if (cookie != null && Context.Session != null && !string.IsNullOrEmpty(Session.SessionID))
{
Response.Cookies.Add(new HttpCookie(aspSessionid, Session.SessionID) { Domain = domain, Path = "/", Expires = DateTime.Now.AddDays(30) });
}
}
}
I use a (Primefaces 3.5) logout button in my application that looks like:
<p:commandButton ajax="false" value="Logout" action="#{loginBean.logout}" />
The bean method looks like:
public String logout() {
ExternalContext externalContext =
FacesContext.getCurrentInstance().getExternalContext();
HttpServletRequest request = (HttpServletRequest) externalContext.getRequest();
try {
request.logout();
System.out.println("Logging out!");
return "/mylogin?faces-redirect=true";
} catch (ServletException ex) {
System.out.println("Failed to logout!");
return null;
}
}
The string Logging out! is printed correctly, but the redirect is not performed!
Only when I click the logout button a second time the login page is displayed again?
Why?
Regards,
G.Verhaag
Change the return statement to
return "mylogin?faces-redirect=true."
Get rid of the slash.
I have a issue when implement spring security remember-me persistent token.
Already successful implement remember-me persistent token, but issue occurs when user logout of system.
Here are implementation:
spring-security.xml
<global-method-security pre-post-annotations="enabled"/>
<http auto-config="true" use-expressions="true" >
...some url parten
<form-login login-page="/login.html"
authentication-failure-url="/loginfailed.html"
authentication-success-handler-ref="customAuthenticationHandler"/>
<logout logout-success-url="/logout.html" delete-cookies='JSESSIONID' />
<remember-me services-ref="pfRememberMeServices"
key="pf_token_key"/>
</http>
<beans:bean id="pfRememberMeServices"
class="org.springframework.security.web.authentication.rememberme.PersistentTokenBasedRememberMeServices">
<beans:property name="tokenRepository" ref="pfTokenRepository" />
<beans:property name="userDetailsService" ref="userDetailsService" />
<beans:property name="tokenValiditySeconds" value="86400"/> <!-- alive in 1 day -->
<beans:property name="key" value="pf_token_key" />
<beans:property name="cookieName" value="mycookie" />
<beans:property name="alwaysRemember" value="true" />
</beans:bean>
<authentication-manager alias="authenticationManager">
<authentication-provider user-service-ref="userDetailsService" />
</authentication-manager>
<beans:bean id="userDetailsService"
class="com.platform.authenticate.model.UserDetailsServiceImpl" >
</beans:bean>.
Token repository:
#Override
public void removeUserTokens(String userid) {
// TODO Auto-generated method stub
tokenDao.removeUserTokens(userid);
}
TokenDao:
#Transactional
public void removeUserTokens(final String username) {
//Session session = getSessionFactory().getCurrentSession();
Session session = HibernateUtil.getSessionFactory().openSession();
Transaction tx = null;
try {
tx = session.beginTransaction();
Token token =
(Token) session.createCriteria(Token.class)
.add(Restrictions.eq("username", username)).uniqueResult();
if (token != null) {
session.delete(token);
}
tx.commit();
} catch (RuntimeException e) {
tx.rollback();
throw e; // or display error message
} finally {
session.close();
}
}
When I login with the same user on two browsers, or two clients, there are two records in persistent_logins table as following:
"2JLIh8E8vifKOdlaidCIog==";"user12";"OKjbqqIAhx74JpmPsNQHaw==";"2013-07-03 16:19:05.12"
"gQ2EDtl87ZC6XSjV6cTYrA==";"user12";"iYrG7dlnjPyKxUz/hwQMdQ==";"2013-07-03 15:47:24.011"
Is my implementation is right when there are two record for the same user?
Then, when I logout from one browser, or one client, the removeUserTokens() function is fired, but:
Token token =
(Token) session.createCriteria(Token.class)
.add(Restrictions.eq("username", username)).uniqueResult();
with above code, I could not remove token for logout user by username, when there are 2 records of user12, it is not unique result.
If I force delete all user12, then all session/token for all clients will be deleted. It is not right?
So how could I remove session/token info for logout user only, but keep session/token for same user on others client?
I have already ask mr google but my issue is seem to be unique, could not find any same one out there.
If my implementation is wrong, please let me know.
Update:
Here are stack trace when I send j_spring_security_logout from one client:
exception
org.hibernate.NonUniqueResultException: query did not return a unique
result: 2
org.hibernate.impl.AbstractQueryImpl.uniqueElement(AbstractQueryImpl.java:899)
org.hibernate.impl.CriteriaImpl.uniqueResult(CriteriaImpl.java:369)
I got same implementation - i got same problem.
But no i decide to delete all tokens, because to look up token for definitely
List<Token> tokens = sessionFactory.getCurrentSession().createCriteria(Token.class)
.add(Restrictions.eq("username", username)).list();
if (tokens.size() > 0) {
for (Token token : tokens) {
sessionFactory.getCurrentSession().delete(token);
}
}
I would like to find the best/elegant/handy way to enable/disable spring security for test and dev environment. I would like to use a property on db, if this property is set to ON then the authentication is mandatory, otherwise the user does not need to authenticate and it reaches the application homepage directly with all roles associated and fake user name/properties.
By the way, my application has a simple authentication strategy: the user logged previously via a different web-application that provides him links to access many other web-app. One of this link redirect to my web-app with a simple submit containing user name and roles, my security chain catches this informations and perform an automatic authentication.
Any suggestion will be appreciated ;)
Bye!
Dolfiz
Some snippet of my code...
SpringSecurityContext.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: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.1.xsd">
<security:http use-expressions="true" auto-config="false" entry-point-ref="preAuthenticatedProcessingFilterEntryPoint">
<security:intercept-url pattern="/fakeLogin*" access="IS_AUTHENTICATED_ANONYMOUSLY" />
<security:intercept-url pattern="/authError*" access="IS_AUTHENTICATED_ANONYMOUSLY" />
<security:intercept-url pattern="/VAADIN**" access="IS_AUTHENTICATED_ANONYMOUSLY" />
<security:intercept-url pattern="/**" access="isAuthenticated()" />
<security:logout logout-url="/logout" logout-success-url="http://milan-ias-vs.usersad.everis.int/DMTest/" invalidate-session="true" />
<security:custom-filter position="PRE_AUTH_FILTER" ref="preAuthenticatedProcessingFilter" />
</security:http>
<bean id="preAuthenticatedProcessingFilterEntryPoint" class="it.ram.authentication.LinkForbiddenEntryPoint" />
<bean id="preAuthenticatedProcessingFilter" class="it.ram.authentication.PreAuthenticatedProcessingFilter">
<property name="authenticationManager" ref="authenticationManager" />
</bean>
<bean id="preauthAuthProvider" class="org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationProvider">
<property name="preAuthenticatedUserDetailsService">
<bean class="it.ram.authentication.PreAuthenticatedUserDetailsService" />
</property>
</bean>
<security:authentication-manager alias="authenticationManager">
<security:authentication-provider ref="preauthAuthProvider" />
</security:authentication-manager>
</beans>
PreAuthenticatedProcessingFilter.java:
public class PreAuthenticatedProcessingFilter extends AbstractPreAuthenticatedProcessingFilter {
private final static Log log = LogFactory.getLog(PreAuthenticatedProcessingFilter.class);
public PreAuthenticatedProcessingFilter() {
super();
log.debug("PreAuthenticatedProcessingFilter default constructor");
setAuthenticationDetailsSource(new CustomAuthenticationDetailsSource());
}
public PreAuthenticatedProcessingFilter(AuthenticationManager authenticationManager) {
log.debug("PreAuthenticatedProcessingFilter constructor with AuthMan arg");
setAuthenticationDetailsSource(new CustomAuthenticationDetailsSource());
}
#Override
protected Object getPreAuthenticatedPrincipal(HttpServletRequest request) {
String userName = request.getParameter(Constants.REQUEST_USER_PARAM);
log.debug("getPreAuthenticatedPrincipal - Returning " +userName);
return userName;
}
#Override
protected Object getPreAuthenticatedCredentials(HttpServletRequest request) {
log.debug("getPreAuthenticatedCredentials - Returning N/A");
return "N/A";
}
public static class CustomAuthenticationDetailsSource implements AuthenticationDetailsSource<HttpServletRequest, SessionUserDetails> {
#Override
public SessionUserDetails buildDetails(HttpServletRequest request) {
log.debug("buildDetails");
// create container for pre-auth data
String role = request.getParameter(Constants.REQUEST_ROLE_PARAM);
return new SessionUserDetails(role);
}
}
}
PreAuthenticatedUserDetailsService.xml:
public class PreAuthenticatedUserDetailsService implements AuthenticationUserDetailsService<PreAuthenticatedAuthenticationToken> {
private final static Log log = LogFactory.getLog(PreAuthenticatedUserDetailsService.class);
#Override
public UserDetails loadUserDetails(PreAuthenticatedAuthenticationToken token) throws UsernameNotFoundException {
log.debug("loadUserDetails - token.getName(): " +token.getName());
SessionUserDetails sessionUserDetails = (SessionUserDetails) token.getDetails();
List<SimpleGrantedAuthority> authorities = sessionUserDetails.getAuthorities();
return new User(token.getName(), "N/A", true, true, true, true, authorities);
}
}
Take a look at:
org.springframework.security.web.authentication.RememberMeServices#autoLogin(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
Poke around here for an implementation:
http://git.springsource.org/spring-security/spring-security/trees/c12c43da9eb59b664bc995a38859c6acac621390/web/src/main/java/org/springframework/security/web/authentication/rememberme
SecurityContextHolder is the place to look if you have existing credentials and to then change or replace them.
SecurityContext securityContext = SecurityContextHolder.getContext();
Authentication authentication = securityContext.getAuthentication();
// authentication contains existing (if set and non-null) maybe it is anonymous
// so then you might have a better set of credentials to replace it with
WebappUserDetails webappUserDetails = userContextService.getPrincipal(WebappUserDetails.class);
// The above constructs my custom type that implement spring UserDetails interface
// this is the identity of the user
// You should check things are valid (account enable and valid, etc..)
// Then you make a fake Authentication and attach it to the session context
// There are many token kinds in spring representing different ways to auth
// this token is the kind that might be used for a HTML form based login with
// username and password.
String principal = "myusername"; // username
String credentials = "mypassword"; // password
// Note you should probably not want to hardwire passwords into code and the correct
// way is to setup a new Token type and configure main security XML to allow it
// to the secure URLs (or secured subjects)
Authentication authRequest = new UsernamePasswordAuthenticationToken(principal, credentials);
Authentication authResult = authenticationManager.authenticate(authRequest);
// Check the authResult then attach it to the context
SecurityContextHolder.getContext().setAuthentication(authResult);