I am trying to create an additional access token for a user within my spring boot application. I do not know their password but the user is authorized to the application. From what I can see I would need to call something like
OAuth2AccessToken accessToken = tokenServices.createAccessTokenForUser(authenticationRequest, user);
Where tokenServices is presumably an instance of DefaultTokenServices. The question is how do I get a reference to the configured token services? I see that this is wired into AuthorizationServerEndpointsConfigurer but I cannot autowire this in. I am using JWT for authentication so really looking for a way to generate a JWT token.
Was trying to implement the flow outlined in Spring OAuth2 - Manually creating an access token in the token store
In my spring-security-config.xml i have this:
<bean id="tokenServices" class="de.hybris.platform.ycommercewebservices.oauth2.token.provider.HybrisOAuthTokenServices">
<property name="tokenStore" ref="tokenStore" />
<property name="supportRefreshToken" value="true" />
<property name="refreshTokenValiditySeconds" value="2592000" />
<!-- 60*60*24*30 = 30d -->
<property name="accessTokenValiditySeconds" value="43200" />
<!-- 60*60*12 = 12h -->
</bean>
Where i can configure my customized tokenServices
public class HybrisOAuthTokenServices extends DefaultTokenServices{
#Override
public OAuth2AccessToken createAccessToken(final OAuth2Authentication authentication) throws AuthenticationException{
try{
return super.createAccessToken(authentication);
}catch (final ModelSavingException e) {
//in case when other client was faster in saving access token - try to get token again
return super.createAccessToken(authentication);
}catch (final ModelRemovalException e) {
//in case when other client was faster in removing expired token - try to get token again
return super.createAccessToken(authentication);
}
}
}
Related
For Spring security setup in Spring Boot. The LDAP Authentication provider is configured by default to use BindAuthenticator class.
This Class contains method
/**
* Allows subclasses to inspect the exception thrown by an attempt to bind with a
* particular DN. The default implementation just reports the failure to the debug
* logger.
*/
protected void handleBindException(String userDn, String username, Throwable cause) {
if (logger.isDebugEnabled()) {
logger.debug("Failed to bind as " + userDn + ": " + cause);
}
}
This Method is to handle the authentication related Exceptions like invalid credentials.
I want to over-ride this method so i can handle this issue and return proper error message on the basis of error codes returned by LDAP. like invalid password or the account is locked.
Current LDAP implementation always returns "Bad Credentials" that does not give the right picture that why my credentials are invalid. i want to cover the cases
where the account is Locked
password is expired so i can redirect to change password
account locked due to number of invalid password retries
Please help
The issue i fixed by defining the LDAP context instead of using the Spring Boot LDAPAuthenticationProviderConfigurer.
Then created the FilterBasedLdapUserSearch and Over-written the BindAuthentication with my ConnectBindAuthenticator.
i created a separate LDAPConfiguration class for spring boot configuration and registered all these custom objects as Beans.
From the above Objects i created LDAPAuthenticationProvider by passing my Custom Objects to constructor
The Config is as below
#Bean
public DefaultSpringSecurityContextSource contextSource() {
DefaultSpringSecurityContextSource contextSource = new DefaultSpringSecurityContextSource(env.getProperty("ldap.url"));
contextSource.setBase(env.getProperty("ldap.base"));
contextSource.setUserDn(env.getProperty("ldap.managerDn"));
contextSource.setPassword(env.getProperty("ldap.managerPassword"));
return contextSource;
}
#Bean
public ConnectBindAuthenticator bindAuthenticator() {
ConnectBindAuthenticator connectBindAuthenticator = new ConnectBindAuthenticator(contextSource());
connectBindAuthenticator.setUserSearch(ldapUserSearch());
connectBindAuthenticator.setUserDnPatterns(new String[]{env.getProperty("ldap.managerDn")});
return connectBindAuthenticator;
}
#Bean
public LdapUserSearch ldapUserSearch() {
return new FilterBasedLdapUserSearch("", env.getProperty("ldap.userSearchFilter"), contextSource());
}
You have to change your spring security configuration to add your extension of BindAuthenticator:
CustomBindAuthenticator.java
public class CustomBindAuthenticator extends BindAuthenticator {
public CustomBindAuthenticator(BaseLdapPathContextSource contextSource) {
super(contextSource);
}
#Override
protected void handleBindException(String userDn, String username, Throwable cause) {
// TODO: Include here the logic of your custom BindAuthenticator
if (somethingHappens()) {
throw new MyCustomException("Custom error message");
}
super.handleBindException(userDn, username, cause);
}
}
spring-security.xml
<beans:bean id="contextSource"
class="org.springframework.security.ldap.DefaultSpringSecurityContextSource">
<beans:constructor-arg value="LDAP_URL" />
<beans:property name="userDn" value="USER_DN" />
<beans:property name="password" value="PASSWORD" />
</beans:bean>
<beans:bean id="userSearch"
class="org.springframework.security.ldap.search.FilterBasedLdapUserSearch">
<beans:constructor-arg index="0" value="USER_SEARCH_BASE" />
<beans:constructor-arg index="1" value="USER_SEARCH_FILTER" />
<beans:constructor-arg index="2" ref="contextSource" />
</beans:bean>
<beans:bean id="ldapAuthProvider"
class="org.springframework.security.ldap.authentication.LdapAuthenticationProvider">
<beans:constructor-arg>
<beans:bean class="com.your.project.CustomBindAuthenticator">
<beans:constructor-arg ref="contextSource" />
<beans:property name="userSearch" ref="userSearch" />
</beans:bean>
</beans:constructor-arg>
</beans:bean>
<security:authentication-manager alias="authenticationManager">
<security:authentication-provider ref="ldapAuthProvider" />
</security:authentication-manager>
Hope it's helpful.
I'm developing a web application using Spring, Vaadin and Apache Shiro for authentication and authorization. I have two realms, since some users log in through a database, others authenticate against LDAP. JDBC realm works perfectly but somehow LDAP realm lets everybody through - no matter what username/password combination is provided.
Here is my Spring configuration:
<!-- Apache Shiro -->
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
<property name="securityManager" ref="securityManager" />
</bean>
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
<property name="realms">
<list>
<ref bean="jdbcRealm" />
<ref bean="ldapRealm" />
</list>
</property>
<property name="authenticator.authenticationStrategy">
<bean class="org.apache.shiro.authc.pam.FirstSuccessfulStrategy" />
</property>
</bean>
<bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor" />
<bean id="ldapContextFactory" class="org.apache.shiro.realm.ldap.JndiLdapContextFactory">
<property name="url" value="ldap://localhost:389" />
</bean>
<bean id="jdbcRealm" class="org.apache.shiro.realm.jdbc.JdbcRealm">
<property name="dataSource" ref="dataSource"></property>
</bean>
<bean id="ldapRealm" class="org.apache.shiro.realm.ldap.JndiLdapRealm">
<property name="contextFactory" ref="ldapContextFactory" />
<property name="userDnTemplate" value="uid={0},ou=people,dc=maxcrc,dc=com" />
</bean>
Logging in is rather typical:
try {
// Obtain user reference
Subject currentUser = SecurityUtils.getSubject();
// Create token using provided username and password
UsernamePasswordToken token = new UsernamePasswordToken(userName, password);
// Remember user
if(rememberMe.getValue())
token.setRememberMe(true);
// Login
currentUser.login(token);
// If we are here, no exception was raised and the user was logged in, so redirect
UI.getCurrent().getNavigator().navigateTo("main" + "/" + "main-page");
// Fire CustomEvent
fireEvent(new CustomEvent(ErasmusLoginForm.this));
} catch ( UnknownAccountException e ) {
Notification.show("No such user...");
} catch ( IncorrectCredentialsException e ) {
Notification.show("Invalid creditentials...");
} catch ( LockedAccountException e ) {
Notification.show("Locked account...");
} catch ( AuthenticationException e ) {
e.printStackTrace();
Notification.show("Some other exception...");
} catch (Exception e) {
// Password encryption exception
}
I read almost everywhere with no luck.
This post (Shiro Authenticates Non-existent User in LDAP) also wasn't helpful to me - both the DN template and the URL are correct and the server (LDAP server) is running. Why does it let everybody through?
If I turn Ldap realm off, JDBC authentication works perfectly. But with both of them on, everybody gets through since I'm using FirstSuccessfulStrategy.
EDIT: Additional note: if I provide an empty password, AuthenticationException is raised. But any non-empty password works fine.
Any ideas?
We are developing RESTful webservices with Spring 3 and we need to have the functionality of login/logout, something like /webservices/login/<username>/<password>/ and /webservices/logout. The session should be stored in the context until the session is timed out or logged out to allow consumption of other webservices. Any request to access webservices without session information should be rejected. Looking for state-of-the-art solution for this scenario.
I am actually resurrecting the question asked here Spring Security 3 programmatically login, which is still not properly answered. Please specify the changes needed in web.xml as well.
I would suggest defining your Spring Security filters completely manually. It's not that difficult, and you get full control over your login/logout behaviour.
First of all, you will need standard web.xml blurb to delegate filter chain handling to Spring (remove async-supported if you are not on Servlet API ver 3):
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<async-supported>true</async-supported>
<filter-class>
org.springframework.web.filter.DelegatingFilterProxy
</filter-class>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
Now, in security context you will define filters separately for each path. Filters can authenticate user, log out user, check security credentials etc.
<bean id="springSecurityFilterChain" class="org.springframework.security.web.FilterChainProxy">
<sec:filter-chain-map path-type="ant">
<sec:filter-chain pattern="/login" filters="sif,wsFilter"/>
<sec:filter-chain pattern="/logout" filters="sif,logoutFilter" />
<sec:filter-chain pattern="/rest/**" filters="sif,fsi"/>
</sec:filter-chain-map>
</bean>
The XML above tells Spring to pass requests to specific context-relative URLs through filter chains. First thing in any of the filter chains is establishing security context - 'sif' bean takes care of that.
<bean id="sif" class="org.springframework.security.web.context.SecurityContextPersistenceFilter"/>
Next filter in chain can now either add data to the security context (read: log in/log out user), or make a decision as to whether allow access based on said security context.
For your login URL you will want a filter that reads authentication data from the request, validates it, and in turn stores it in security context (which is stored in session):
<bean id="wsFilter" class="my.own.security.AuthenticationFilter">
<property name="authenticationManager" ref="authenticationManager"/>
<property name="authenticationSuccessHandler" ref="myAuthSuccessHandler"/>
<property name="passwordParameter" value="pass"></property>
<property name="usernameParameter" value="user"></property>
<property name="postOnly" value="false"></property>
You can use Spring generic UsernamePasswordAuthenticationFilter but the reason I use my own implementation is to continue filter chain processing (default implementation assumes user will get redirected on successful auth and terminates filter chain), and being able to process authentication every time username and password is passed to it:
public class MyAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
#Override
protected boolean requiresAuthentication(HttpServletRequest request, HttpServletResponse response) {
return ( StringUtils.hasText(obtainUsername(request)) && StringUtils.hasText(obtainPassword(request)) );
}
#Override
protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain,
Authentication authResult) throws IOException, ServletException{
super.successfulAuthentication(request, response, chain, authResult);
chain.doFilter(request, response);
}
You can add any number of your own filter implementations for /login path, such as authentication using HTTP basic auth header, digest header, or even extract username/pwd from the request body. Spring provides a bunch of filters for that.
I have my own auth success handler who overrides the default redirect strategy:
public class AuthenticationSuccessHandler extends SimpleUrlAuthenticationSuccessHandler {
#PostConstruct
public void afterPropertiesSet() {
setRedirectStrategy(new NoRedirectStrategy());
}
protected class NoRedirectStrategy implements RedirectStrategy {
#Override
public void sendRedirect(HttpServletRequest request,
HttpServletResponse response, String url) throws IOException {
// no redirect
}
}
}
You don't have to have custom auth success handler (and probably custom auth filter as well) if you're ok with user being redirected after successful login (redirect URL can be customized, check docs)
Define authentication manager who will be responsible for retrieving user's details:
<sec:authentication-manager alias="authenticationManager">
<sec:authentication-provider ref="myAuthAuthProvider"/>
</sec:authentication-manager>
<bean id="myAuthAuthProvider" class="org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationProvider">
<property name="preAuthenticatedUserDetailsService">
<bean id="userDetailsServiceWrapper" class="org.springframework.security.core.userdetails.UserDetailsByNameServiceWrapper">
<property name="userDetailsService" ref="myUserDetailsImpl"/>
</bean>
</property>
</bean>
You will have to provide your own user details bean implementation here.
Logout filter: responsible for clearing security context
<bean id="logoutFilter" class="org.springframework.security.web.authentication.logout.LogoutFilter">
<constructor-arg>
<list>
<bean class="org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler"/>
</list>
</constructor-arg>
</bean>
Generic authentication stuff:
<bean id="httpRequestAccessDecisionManager" class="org.springframework.security.access.vote.AffirmativeBased">
<property name="allowIfAllAbstainDecisions" value="false"/>
<property name="decisionVoters">
<list>
<ref bean="roleVoter"/>
</list>
</property>
</bean>
<bean id="roleVoter" class="org.springframework.security.access.vote.RoleVoter"/>
<bean id="securityContextHolderAwareRequestFilter" class="org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter"/>
Access control filter (should be self-explanatory):
<bean id="fsi" class="org.springframework.security.web.access.intercept.FilterSecurityInterceptor">
<property name="authenticationManager" ref="myAuthenticationManager"/>
<property name="accessDecisionManager" ref="httpRequestAccessDecisionManager"/>
<property name="securityMetadataSource">
<sec:filter-invocation-definition-source>
<sec:intercept-url pattern="/rest/**" access="ROLE_REST"/>
</sec:filter-invocation-definition-source>
</property>
</bean>
You should also be able to secure your REST services with #Secured annotations on methods.
Context above was plucked from existing REST service webapp - sorry for any possible typos.
It is also possible to do at least most of what is implemented here by using stock sec Spring tags, but I prefer custom approach as that gives me most control.
Hope this at least gets you started.
I want to display a custom error page on authentication denial (I am using a pre-authenticated secnario) and also access denial from Spring Security 3.0.X
Understand we can use the following to perform this:
<beans:bean id="authenticationEntryPoint" class="org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint">
<beans:property name="loginFormUrl" value="/error.jsp"/>
</beans:bean>
<beans:bean id="accessDeniedHandler" class="org.springframework.security.web.access.AccessDeniedHandlerImpl">
<beans:property name="errorPage" value="/error.jsp"/>
</beans:bean>
but doing this results in a redirect and not a forward to the error page. Anyway to perform forward to an error page (so that we can set some attributes in the request)
Thanks
In my security-context.xml, for authentication failure I do like this (pay attention to the authentication-failure-url attribute):
<security:form-login login-page="/auth/login"
authentication-failure-url="/auth/login?error=true"
default-target-url="/mvc/home"
always-use-default-target="true" />
And for access denied I use this:
<security:access-denied-handler error-page="/auth/access-denied"/>
Both tags inside <security:http use-expressions="true">. For me works like a charm, I don't know why you are trying to configure it in the way you are doing when Spring provides such nice tags easy to use.
I don't know if it answers your question, I hope it helps.
EDIT:
Using the configuration provided above, means that you are using the default authentication failure handler (SimpleUrlAuthenticationFailureHandler) at the background. You can change the default behavior (which as default performs a redirect when a failed authentication is produced) by changing the attribute forwardToDestination value. This is what SimpleUrlAuthenticationFailureHandler does:
/**
* Performs the redirect or forward to the {#code defaultFailureUrl} if set, otherwise returns a 401 error code.
* <p>
* If redirecting or forwarding, {#code saveException} will be called to cache the exception for use in
* the target view.
*/
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response,
AuthenticationException exception) throws IOException, ServletException {
if (defaultFailureUrl == null) {
logger.debug("No failure URL set, sending 401 Unauthorized error");
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Authentication Failed: " + exception.getMessage());
} else {
saveException(request, exception);
if (forwardToDestination) {
logger.debug("Forwarding to " + defaultFailureUrl);
request.getRequestDispatcher(defaultFailureUrl).forward(request, response);
} else {
logger.debug("Redirecting to " + defaultFailureUrl);
redirectStrategy.sendRedirect(request, response, defaultFailureUrl);
}
}
}
So I guess that I you declare your SimpleUrlAuthenticationFailureHandler in your security-context.xml and set the mentioned property value using the setUseForward(boolean forwardToDestination) method it should work. Could be something like:
<bean id="simpleUrlAuthenticationFailureHandler" class="org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler">
<property name="useForward" value="true">
</bean>
And then:
<security:form-login login-page="/auth/login"
authentication-failure-handler-ref="simpleUrlAuthenticationFailureHandler"
default-target-url="/mvc/home"
always-use-default-target="true" />
Good luck.
I need to de-authenticate a user (kill their session) within my spring security 3.0.5 web app and then send a redirect to another site to notify them of the logout. Is this possible within spring and if so what is the general approach to performing these tasks? Thanks!
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.logout.SimpleUrlLogoutSuccessHandler;
import com.dc.api.model.Users;
public class DCSimpleUrlLogoutSuccessHandler extends SimpleUrlLogoutSuccessHandler{
public void onLogoutSuccess(javax.servlet.http.HttpServletRequest request,
javax.servlet.http.HttpServletResponse response,
Authentication authentication)
throws java.io.IOException,
javax.servlet.ServletException{
Users user=null;
Object principal = authentication.getPrincipal();
if (principal instanceof Users) {
user = (Users) principal;
if(user.getType().equals(TEST)){
response.sendRedirect("LogoutServlet");
}
}
response.sendRedirect("login.html");
}
}
java.lang.IllegalStateException
org.apache.catalina.connector.ResponseFacade.sendRedirect(ResponseFacade.java:463)
javax.servlet.http.HttpServletResponseWrapper.sendRedirect(HttpServletResponseWrapper.java:138)
org.springframework.security.web.context.SaveContextOnUpdateOrErrorResponseWrapper.sendRedirect(SaveContextOnUpdateOrErrorResponseWrapper.java:74)
com.dc.api.service.impl.DCSimpleUrlLogoutSuccessHandler.onLogoutSuccess(DCSimpleUrlLogoutSuccessHandler.java:24)
org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:100)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:380)
org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:79)
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:380)
org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:169)
org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:237)
org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:167)
Actually the marked "correct answer" is about setting a custom logout success-handler, but not LogoutFilter , as defining in question.
So, if someone wants to create a custom logout filter, here is a snippet:
<bean id="securityContextLogoutHandler" class="org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler"/>
<bean id="logoutFilter" class="org.springframework.security.web.authentication.logout.LogoutFilter">
<property name="filterProcessesUrl" value="/logout"/>
<constructor-arg index="0" value="/"/>
<constructor-arg index="1">
<list>
<ref bean="securityContextLogoutHandler"/>
<!--ref bean="myLogoutHandler"/-->
</list>
</constructor-arg>
</bean>
This is a default filter class with one default predefined handler (this one invalidate session).
If you really need a custom logout filter, then you should change this standard behavior (subclass this or write your own with the same interface).
Also don't forget to register it:
<security:http>
....
<custom-filter position="LOGOUT_FILTER" ref="logoutFilter"/>
</security:http>
UPDATE:
After reading some spring code, I found, that there is one more default logout handler - RememberMeServices, defined with the interface AbstractRememberMeServices implements LogoutHandler. So if you are using RememberMeServices and want to write a custom filter including RememberMe support, you also need add a reference to your RememberMeServices in list of logout handlers.
Subclass SimpleUrlLogoutSuccessHandler and override onLogoutSuccess() to do the redirect.
Configure the logout success handler like:
<http>
...
<logout success-handler-ref="myLogoutSuccessHandler"/>
</http>