When I configure Spring Security 3 to log out the user I get a huge error
Exception in thread ""http-bio-8080"-exec-7" java.lang.StackOverflowError
at com.dc.api.model.Users.getUsername(Users.java:200)
The Users.java:200 maps to the org.springframework.security.core.userdetails.UserDetails implementation method
public String getUsername() {
return this.getUsername();
}
log out link:
<a href="${facesContext.externalContext.requestContextPath}/j_spring_security_logout.html">
log out</a>
spring security config:
<logout invalidate-session="true"
logout-success-url="/"
logout-url="/j_spring_security_logout.html"/>
web.xml:
I've configured the springSecurityFilterChain to run on any forward or request to *.html and *.xhtml
The issue here was the below method thats called by spring security was calling itself and was in an infinite loop. It should be calling my User model object's userId (this.getUserId)
public String getUsername() {
return this.getUsername();
}
Related
I tried to do LDAP authentication using spring security using below configuration. The authentication was successful.
<authentication-manager>
<ldap-authentication-provider
user-search-filter="(uid={0})"
user-search-base="ou=people"
>
</ldap-authentication-provider>
</authentication-manager>
<ldap-server url="ldap://ldap.XXX.net/dc=XXX,dc=com" manager-dn="dc=XXX,dc=com" manager-password="" />
Now I need to get user details like domain ,organization etc from ldap itself,through java I am able to get the results using by calling search method of LdapContext. Is there a similar way to get the details required using spring security after successful authentication?
LdapContext ctx = null;
NamingEnumeration<SearchResult> results = null;
results = ctx.search(baseDn,searchFilter,controls);
You can use the userContextMapper property on the ldap authentication provider:
<authentication-manager>
<ldap-authentication-provider
user-search-filter="(uid={0})"
user-search-base="ou=people"
user-context-mapper-ref="customUserContextMapper" />
>
</ldap-authentication-provider>
</authentication-manager>
public class CustomUserContextMapper extends LdapUserDetailsMapper {
#Override
public UserDetails mapUserFromContext(DirContextOperations ctx, String username, Collection<? extends GrantedAuthority> authorities) {}
}
You can then use ctx to query necessary information.
I'm using spring/spring-security 3.1 and want to take some action depends on the authorities in ATHENTICATION object whenever session is timed out.AUTHENTICATION object is null on session timeout.
Here are the files for reference:
security config:
<logout invalidate-session="true" logout-url="/j_spring_security_logout" success-handler-ref="logoutSuccessHandler"/>
<!-- Custom filter to deny unwanted users even though registered -->
<custom-filter ref="blacklistFilter" before="FILTER_SECURITY_INTERCEPTOR" />
<!-- Custom filter for username, password and domain. The real customization is done in the customAuthenticationManager -->
<custom-filter ref="authenticationFilter" position="FORM_LOGIN_FILTER" />
</http>
Note: tried with "invalidate-session="false"" as well.
and my custom LogoutSuccessHandler:
public class EnterpriseLogoutSuccessHandler extends SimpleUrlLogoutSuccessHandler{
#Override
public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
for(GrantedAuthority authority: authentication.getAuthorities()){
if(authority.getAuthority()!=null)
logger.debug("THE CURRENT AUTHORITY FOR THE SESSION IS : {} ",authority.getAuthority().toString());
else
logger.debug("THE CURRENT AUTHORITY FOR THE SESSION IS authority.getAuthority(): NULL ");
if(authority.getAuthority()!=null && authority.getAuthority().equalsIgnoreCase(Operational.SPRING_SECURITY.LOGIN_SOURCE_BEACON)){
loginSource = authority.getAuthority().toString();
break;
}
}
}
}
So, there is the question how I can obtain Authentication object on the session timeout.
Can some help me to find out the solution for the above problem.
Thanks in advance.
I am currently trying to setup a project with these main technologies:
Java EE 7
EJB 3.2
JAX-RS (Jersey) 2.0
Glassfish 4
Spring Security 3.1.5
I saw that it is possible to write something like that
#Stateless
#Path("apath")
public class WebResource {
#EJB
private SomeService serviceInjected;
#GET
public Response doSomething() {
return Response.ok(injectedService.doSomethingElse()).build();
}
}
Then, this means that the SomeService Session Bean is injected by the container and once we call the path: :///apath, everything is working fine.
Now, what I try to achieve is to integrate the SpringSecurity framework in that code. So my code become this:
#Component
#Stateless
#Path("apath")
public class WebResource {
#EJB
private SomeService serviceInjected;
#GET
#PreAuthorized("hasPermission('ROLE_SOMETHING')")
public Response doSomething() {
return Response.ok(injectedService.doSomethingElse()).build();
}
}
But, this does not work. Everything excepted the SpringSecurity annotations continue to work. The authorization annotations are just not taken into account.
In SpringSecurity configuration file, I have something like that:
<security:global-method-security
access-decision-manager-ref="preVoteAccessDecisionManager"
pre-post-annotations="enabled" />
with everything related to the filter chain and so correctly configured. For example, I have that:
<beans:bean id="securityInterceptor" class="org.springframework.security.web.access.intercept.FilterSecurityInterceptor">
<beans:property name="securityMetadataSource">
<security:filter-security-metadata-source>
<security:intercept-url pattern="/**" access="ROLE_TEST" />
</security:filter-security-metadata-source>
</beans:property>
<beans:property name="authenticationManager" ref="authenticationManager" />
<beans:property name="accessDecisionManager" ref="accessDecisionManager" />
</beans:bean>
And I see in my Glassfish 4 server logs that SpringSecurity managed the ROLE_TEST access for my authenticated user. I also see that my user authenticated has the list of roles that I expect.
I also tried to use this configuration and rely on javax.annotation.security annotations as below:
<security:global-method-security
access-decision-manager-ref="preVoteAccessDecisionManager"
jsr250-annotations="enabled" />
#Stateless
#Path("apath")
public class WebResource {
#EJB
private SomeService serviceInjected;
#GET
#RolesAllowed("ROLE_SOMETHING")
public Response doSomething() {
return Response.ok(injectedService.doSomethingElse()).build();
}
}
This time, the annotation is working and an exception is thrown when the user is authenticated. But in this case, my user has the roles but the SecurityContext used by the container is not filled with the Principal and roles information related to the user authenticated by SpringSecurity.
Finally, my question(s). Is there a way to integrate the JAX-RS / #Stateless / SpringSecurity Authorization together? If not, is there a way to fill a SecurityContext from SrpingSecurity to allow javax.annotation.security to work like a charm?
Thanks in advance for any helps, tips, tricks or anything else that can solve my problems :D
Spring Security's method security annotations will normally only work with Spring beans whose lifecycle is controlled by Spring. This doesn't include EJBs. However, if you wish you can use the AspectJ integration which will work for any object including EJB instances. There's a sample application in the Spring Security codebase which you can use as a reference. It might also be worth considering whether you need to use EJBs at all.
How to get username or UserDetail object in logout-success-url? Below is my configuration:
<form-login default-target-url="/security/loginSuccess.action"
always-use-default-target="false"
authentication-failure-url="/security/loginFailed.action"
login-page="/security/restrictUser.action"/>
<logout invalidate-session="true" logout-success-url="/security/logoutUser.action" />
<session-management
session-authentication-strategy-ref="customMsgAwareConcurrentSessionControlStartegy"
invalid-session-url="/security/logoutUser.action"/>
I want to get the username who has requested for logout within logout-success-url (for me it is a Struts 2 action method). I have checked SecurityContextHolder, but it seems that SecurityContextHolder is cleared when the control reaches my action method in logout-success-url.
Use custom LogoutSuccessHandler for that. Inside your configuration define bean and use success-handler-ref attribute of <logout> tag.
<logout success-handler-ref="customLogoutSuccessHandler" />
<beans:bean id="customLogoutSuccessHandler" class="..." />
And inside CustomLogoutSuccessHandler there is onLogoutSuccess method which has Authentication argument.
public class CustomLogoutSuccessHandler extends
AbstractAuthenticationTargetUrlRequestHandler implements
LogoutSuccessHandler {
public void onLogoutSuccess(HttpServletRequest request,
HttpServletResponse response, Authentication authentication)
throws IOException, ServletException {
// use authentication to get user name
}
}
I want to log every login in my web application. I was able to access the logins which take place through UsernamePasswordAuthenticationFilter but I don't know how to log users who log in using remember-me functionality. I tried overriding the
createSuccessfulAuthentication(HttpServletRequest request, UserDetails user)
of TokenBasedRememberMeServices, but then logouts are recorded too, because the remember-me service re-authenticates the user.
The best way of logging authentication success and failures is to use a Spring ApplicationListener.
Spring Security publishes various events for authentication success and failure which you can listen for. Events are also published when access is denied to a resource.
You can look at LoggerListener as an example. Start by adding one of those to your application context and it will automatically log authentication events at warn level.
Regarding remember-me logins, if you logout and then access the site immediately afterwards, and are re-authenticated using a remember-me cookie, then technically that is the same as any other remember-me authentication, so there's not much you can do about it.
However, if your logout success URL is passing through the remember-me filter, and that is how the new session is being created (without any additional action from the user), then simply omit it that page from the security filter chain.
For logging each sucessful login i think best way is to create LoginSucessHandler and specify authentication-success-handler for normal login as well as remember-me. i have done this with below code and configuration.
#Service
public class LoginSucessHandler extends
SavedRequestAwareAuthenticationSuccessHandler {
#Override
public void onAuthenticationSuccess(HttpServletRequest request,
HttpServletResponse response, Authentication authentication)
throws ServletException, IOException {
User user = (User) authentication.getPrincipal();
// record login success of user
super.onAuthenticationSuccess(request, response, authentication);
}
}
<http auto-config="true" use-expressions="true">
<form-login login-page="/login"
authentication-failure-url="/login.hst?error=true"
**authentication-success-handler-ref="loginSucessHandler"** />
<logout invalidate-session="true" logout-success-url="/home"
logout-url="/logout" />
<remember-me key="jbcp" **authentication-success-handler-ref="loginSucessHandler"**/>
<session-management>
<concurrency-control max-sessions="1" />
</session-management>
</http>
I think in your case will help solution when you will use your custom filter, which will intercept every request to your application. In this filter you can log username for every request.
Here I described how to add your custom filter. You just need to change functionality to what you want. And don't forhet to put your filter after security filter chain in web.xml.