spring security oauth2 login using database - spring-security-oauth2

I have created a REST service using spring and security with oauth2 currently when I hit the url I get the access token and then using it I send my basic login credentials which is static in my file in the spring_security.xml file.
How can I provide user authentication using database?
<authentication-manager alias="authenticationManager"
xmlns="http://www.springframework.org/schema/security">
<authentication-provider>
<user-service>
<user name="majid" password="majid" authorities="ROLE_APP" />
<user name="majid1" password="majid1" authorities="ROLE_USER" />
</user-service>
</authentication-provider>
</authentication-manager>

You have to provide your custom implementation of AuthenticationProvider interface
<security:authentication-manager alias="authenticationManager">
<security:authentication-provider ref="authenticationProvider"/>
</security:authentication-manager>
<bean id="authenticationProvider"
class="com.mycompany.security.MyDatabaseAuthenticationProvider"/>
Implementation would look sth. like this
public class MyDatabaseAuthenticationProvider implements AuthenticationProvider {
#Override
public Authentication authenticate(final Authentication authentication) {
final String username = (String) authentication.getPrincipal();
final String password = (String) authentication.getCredentials();
// perform your database stuff and return Authentication object
}
}

Related

loadUserByUsername getting called twice (Spring security)

I am trying to implement a feature where users can login either by userid or by email address. In order to achieve this I am implementing my own UserDetailsService and overriding loadUserByUsername method.
The problem I am facing is that the method loadUserByUsername is called twice whenever I am trying to authenticate. I am new to spring framework and am finding it difficult to trace why is this happening. Appreciate if someone can point me to the right direction to fix this.
spring-security.xml
<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-4.0.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-4.0.xsd">
<http auto-config="true" use-expressions="true">
<csrf disabled="true"/>
<form-login login-processing-url="/login" login-page='/showlogin' default-target-url='/' authentication-failure-url='/authentication-failure' />
<intercept-url pattern="/secureview/**" access="hasRole('ROLE_USER')" />
<remember-me key="patternMinder"/>
<logout logout-url="/logout" logout-success-url="/?logout" />
</http>
<beans:bean id='userDetailsService' class='com.pmz.charting.security.UserDetailServiceImpl'>
</beans:bean>
<authentication-manager alias="authenticationManager">
<authentication-provider user-service-ref="userDetailsService" >
</authentication-provider>
</authentication-manager>
</beans:beans>
UserDetailServiceImpl:
public class UserDetailServiceImpl implements UserDetailsService{
#Override
public UserDetails loadUserByUsername(String user) throws UsernameNotFoundException {
System.out.println("In loadUserByUsername:" + user);
return buildUserFromUserEntity();
}
private UserDetails buildUserFromUserEntity() {
// convert model user to spring security user
String username = "testuser#test.com";
String password = "testuser";
boolean enabled = true;
boolean accountNonExpired = true;
boolean credentialsNonExpired = true;
boolean accountNonLocked = true;
Collection<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
authorities.add(new SimpleGrantedAuthority("ROLE_USER"));
UserDetails springUser = new User(username, password, enabled, accountNonExpired, credentialsNonExpired, accountNonLocked, authorities);
return springUser;
}
}
Output in logs -
In loadUserByUsername:testuser#test.com
In loadUserByUsername:testuser#test.com
For ease of understanding I have hard coded userid and password values.

Intercepting Requests Using Spring Security Rather Than putting pre-handler Interceptor

I am building a Spring MVC web-application. I want to intercept the request with some business logic of validating token stored in database. I want some alternative to HandlerInterceptor's preHandle method. I am trying to implement the same with Spring Security.Please suggest some way.
EDIT
This is how I intercept all requests in my web application :
public class RequestInterceptor implements HandlerInterceptor {
Logger log = LoggerFactory.getLogger(RequestInterceptor.class);
#Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object handler) throws Exception {
//I validate user's token from my database here
//return true if valid token else false
}
}
My servlet-context.xml looks like
<mvc:interceptors>
<bean class="com.clarice.rest.security.RequestInterceptor">
<property name="XXX">
<list>
<value>YYY</value>
</list>
</property>
</bean>
</mvc:interceptors>
So my question is , Is there any way to implement the same interceptor kind of thing using Spring Security writing my own code as I do in RequestInterceptor class ?

Spring Security ignoring access-denied-handler with Method Level Security

I'm using Spring 3.2.4 and am unable to get Spring Security to redirect to my access-denied-handler when using Annotation based method level security. I have found several different posts about this, but to date, there does not seem to be any solutions that I have found.
My security.xml file:
<!-- need this here to be able to secure methods in components other than controllers (as scanned in applicationContext.xml) -->
<global-method-security secured-annotations="enabled" pre-post-annotations="enabled" jsr250-annotations="enabled" ></global-method-security>
<!-- Annotation/JavaConfig examples http://stackoverflow.com/questions/7361513/spring-security-login-page -->
<http use-expressions="true" entry-point-ref="authenticationEntryPoint">
<access-denied-handler ref="accessDeniedHandler"/>
<intercept-url pattern="/secure/login" access="permitAll" />
<intercept-url pattern="/secure/logout" access="permitAll" />
<intercept-url pattern="/secure/denied" access="permitAll" />
<session-management session-fixation-protection="migrateSession" session-authentication-error-url="/login.jsp?authFailed=true">
<concurrency-control max-sessions="10" error-if-maximum-exceeded="true" expired-url="/login.html" session-registry-alias="sessionRegistry"/>
</session-management>
<intercept-url pattern="/**" access="isAuthenticated()" />
<form-login default-target-url="/" authentication-failure-url="/secure/denied" />
<logout logout-url="/secure/logout" logout-success-url="/" />
<expression-handler ref="defaultWebSecurityExpressionHandler" />
</http>
<beans:bean id="authenticationEntryPoint" class="com.ia.security.LoginUrlAuthenticationEntryPoint">
<beans:constructor-arg name="loginFormUrl" value="/secure/login"/>
</beans:bean>
<beans:bean id="accessDeniedHandler" class="com.ia.security.AccessDeniedHandlerImpl">
<beans:property name="errorPage" value="/secure/denied"/>
</beans:bean>
My AccessDeniedHandlerImpl.java :
public class AccessDeniedHandlerImpl extends org.springframework.security.web.access.AccessDeniedHandlerImpl {
// SLF4J logger
private static final Logger logger = LoggerFactory.getLogger(AccessDeniedHandlerImpl.class);
#Override
public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException {
logger.log("AccessDeniedException triggered!");
super.handle(request, response, accessDeniedException);
}
}
My Annotated Method:
#PreAuthorize("hasAuthority('ROLE_ZZZZ')")
public ModelAndView getUserInfo( #PathVariable long userId ){
ModelAndView mv = new ModelAndView();
User u = userService.findUser( userId );
mv.addObject("user", u);
return mv;
}
Is there anything special I need to do such that my access-denied-handler is called?
After several hours of searching around and tracing Spring code, I finally discovered what was happening. I am listing this here in case it is of value to someone else.
The access-denied-handler is used by the ExceptionTranslationFilter in case of an AccessDeniedException. However, the org.springframework.web.servlet.DispatcherServlet was first trying the handle the exception. Specifically, I had a org.springframework.web.servlet.handler.SimpleMappingExceptionResolver defined with a defaultErrorView. Consequently, the SimpleMappingExceptionResolver was consuming the exception by redirecting to an appropriate view, and consequently, there was no exception left to bubble up to the ExceptionTranslationFilter.
The fix was rather simple. Configure the SimpleMappingExceptionResolver to ignore all AccessDeniedException.
<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
<property name="defaultErrorView" value="uncaughtException" />
<property name="excludedExceptions" value="org.springframework.security.access.AccessDeniedException" />
<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>
Now, whenever an AccessDeniedException is thrown, the resolver ignores it and allows it to bubble up the stack to the ExceptionTranslationFilter which then calls upon the access-denied-handler to handle the exception.
I run into the same issue. In my case there was already a #ControllerAdvise definied which should handle exceptions - so I added the AccessDeniedException directly:
#Component
#ControllerAdvice
public class ControllerBase {
...
#ExceptionHandler(value = AccessDeniedException.class)
public ModelAndView accessDenied() {
return new ModelAndView("redirect:login.html");
}
}
Good luck with it!
Extending the Erics answer with JavaConfig for SimpleMappingExceptionResolver to ignore AccessDeniedException so that it can be thrown as response and doesn't get swallowed by the SimpleMappingExceptionResolver.
#Configuration
#EnableWebMvc
public class AppConfig extends WebMvcConfigurerAdapter {
#Bean
public SimpleMappingExceptionResolver exceptionResolver() {
SimpleMappingExceptionResolver exceptionResolver = new SimpleMappingExceptionResolver();
exceptionResolver.setExcludedExceptions(AccessDeniedException.class);
return exceptionResolver;
}
}
Added on to Jessi answer above (https://stackoverflow.com/a/25948861/13215486). Note that if you want to tell the difference between Access Denied, and Access Forbidden, then you need to do a little more work.
#Component
#ControllerAdvice
public class ControllerBase {
...
#ExceptionHandler(value = AccessDeniedException.class)
public ModelAndView accessDenied(HttpServletRequest request) {
ModelAndView mav = new ModelAndView("redirect:login.html");
mav.setStatus(request.getRemoteUser() != null ? HttpStatus.FORBIDDEN : HttpStatus.UNAUTHORIZED);
return mav;
}
}

Avoid going to the previous page after logging out of the website in a spring mvc application

I have made a spring M V C application in which i have provided a log out feature.
But whenever i log out of the system and press the back key i am redirected to the previous page which should not happen in ideal case on logging out.
please help me on how to avoid this.
My controller part for log out is as under:
#RequestMapping( value="/logout",method = RequestMethod.GET)
public ModelAndView logout(HttpServletRequest request, HttpServletResponse response, HttpSession session)
{
session=request.getSession(false);
if(session!=null)
{
l.info(""+session.getAttribute("username"));
session.invalidate();
}
response.setHeader("Cache-Control","no-cache");
response.setHeader("Pragma","no-cache"); //HTTP 1.0
response.setHeader("Cache-Control","no-store"); //HTTP 1.1
response.setDateHeader ("Expires", 0); //prevents caching at the proxy server
String redirect="jsp/index";
return new ModelAndView(redirect);
}
I have tried it and it is working fine for me.
Add this handler to your spring security file
<logout success-handler-ref="logoutSuccessHandler"
invalidate-session="true" delete-cookies="JSESSIONID" />
<beans:bean id="logoutSuccessHandler"
class="com.neosyn.security.CustomLogoutSuccessHandler">
<beans:property name="useReferer" value="true" />
</beans:bean>
define class logout handler
public class CustomLogoutSuccessHandler extends SimpleUrlLogoutSuccessHandler {
#Override
public void onLogoutSuccess(HttpServletRequest request,
HttpServletResponse response, Authentication authentication)
throws IOException, ServletException {
setAlwaysUseDefaultTargetUrl(true);
setDefaultTargetUrl("/home");
super.onLogoutSuccess(request, response, authentication);
}
}

Spring security:How to map j_spring_security_check in controller?

I'm trying to integrate spring security into existing code base which is in spring mvc.
In my existing code base i v'e a client delegate in web project which interacts with service delegate in service project which in turn interacts with service interface of back-end layer.It is the service interface impl of back-end layer which i'm making implement the UserDetailsService interface.
P.S - I'm creating/converting/passing on various objects i.e. Model,DO,DTO,Request,Response etc across all the layers.
So now,when i click on submit i want the control to go through the delegate from web to back-end layer till the class which implements UserDetailsService interface. How can i achieve this?
[Update]:After going through this link i changed my security xml like shown below:
<security:http auto-config="true" use-expressions="true">
<security:intercept-url pattern="/welcome.html" access="hasRole('ROLE_USER')" />
<security:form-login login-page="/portalLogin.html" login-processing-url="/signIn" always-use-default-target="true"
username-parameter="username" password-parameter="password"
default-target-url="/welcome.html" authentication-failure-url="/loginfailed.html" />
<security:logout logout-success-url="/logout.html" />
</security:http>
My LoginController is like this:
#RequestMapping("/signIn")
public ModelAndView onClickLogin(#ModelAttribute("dashboard")
LoginModel loginModel,Model model){
try{
delegate.clickLogin(loginModel);
if(null != loginModel.getError()){
// return new ModelAndView("error");
}
}catch(Exception exception){
}
return new ModelAndView("redirect:welcome.html");
}
[Update]:Sorry for very late update.Controller Mapping issue is resolved, now i'm facing issues because of UsernamePasswordAuthenticationFilter.After comparing logs generated by above code with properly working code logs,i figured out that spring security is not firing 'UsernamePasswordAuthenticationFilter' for some reasons in my case.'UsernamePasswordAuthenticationFilter' is the one which authenticates the user.
//Logs when authentication is done
[while using spring's default /j_spring_security_check].
DEBUG FilterChainProxy - /j_spring_security_check at position 3 of 10 in additional filter chain; firing Filter: 'UsernamePasswordAuthenticationFilter'
DEBUG UsernamePasswordAuthenticationFilter - Request is to process authentication
DEBUG ProviderManager - Authentication attempt using org.springframework.security.authentication.dao.DaoAuthenticationProvider
session created
DEBUG SessionImpl - Opened session at timestamp: 13661947944
SessionImpl(PersistenceContext[entityKeys=[],collectionKeys=[]];ActionQueue[insertions=[] updates=[] deletions=[] collectionCreations=[] collectionRemovals=[] collectionUpdates=[] unresolvedInsertDependencies=UnresolvedEntityInsertActions[]])
After openSession
DEBUG SessionImpl - Opened session at timestamp: 13661947944
Criteria before eq::this::CriteriaImpl(com.infy.itrade.core.entity.LoginDO:this[][])::CriteriaImpl(com.infy.itrade.core.entity.LoginDO:this[][])...
//Logs when authentication is not done [while using custom login processing url : /signIn.html].
DEBUG FilterChainProxy - /signIn.html at position 3 of 10 in additional filter chain; firing Filter: 'UsernamePasswordAuthenticationFilter' //UsernamePasswordAuthenticationFilter is not doing authentication process instead it skips to next filter.
DEBUG FilterChainProxy - /signIn.html at position 4 of 10 in additional filter chain; firing Filter: 'BasicAuthenticationFilter'
DEBUG FilterChainProxy - /signIn.html at position 5 of 10 in additional filter chain; firing Filter: 'RequestCacheAwareFilter'
I created a custom filter 'MyFilter' which extends 'AbstractAuthenticationProcessingFilter'. But still 'MyFilter' doesn't do any authentication as the log shows the following:
DEBUG FilterChainProxy - /signIn.html at position 2 of 9 in additional filter chain; firing Filter: 'LogoutFilter'
DEBUG FilterChainProxy - /signIn.html at position 3 of 9 in additional filter chain; firing Filter: 'MyFilter'
DEBUG FilterChainProxy - /signIn.html at position 4 of 9 in additional filter chain; firing Filter: 'RequestCacheAwareFilter'
MyFilter:
public class MyFilter extends AbstractAuthenticationProcessingFilter {
private static final String DEFAULT_FILTER_PROCESSES_URL = "/signIn";
private static final String POST = "POST";
public static final String SPRING_SECURITY_FORM_USERNAME_KEY = "username";
public static final String SPRING_SECURITY_FORM_PASSWORD_KEY = "password";
public static final String SPRING_SECURITY_LAST_USERNAME_KEY = "SPRING_SECURITY_LAST_USERNAME";
private String usernameParameter = SPRING_SECURITY_FORM_USERNAME_KEY;
private String passwordParameter = SPRING_SECURITY_FORM_PASSWORD_KEY;
public MyFilter() {
super(DEFAULT_FILTER_PROCESSES_URL);
}
public MyFilter(String defaultFilterProcessesUrl) {
super(defaultFilterProcessesUrl);
// TODO Auto-generated constructor stub
}
#Override
public Authentication attemptAuthentication(HttpServletRequest request,
HttpServletResponse arg1) throws AuthenticationException,
IOException, ServletException {
// TODO Auto-generated method stub
String username = obtainUsername(request);
String password = obtainPassword(request);
if (username == null) {
username = "";
}
if (password == null) {
password = "";
}
username = username.trim();
UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(
username, password);
HttpSession session = request.getSession(false);
if (session != null || getAllowSessionCreation()) {
request.getSession().setAttribute(
SPRING_SECURITY_LAST_USERNAME_KEY,
TextEscapeUtils.escapeEntities(username));
}
setDetails(request, authRequest);
return this.getAuthenticationManager().authenticate(authRequest);
}
#Override
public void doFilter(ServletRequest req, ServletResponse res,
FilterChain chain) throws IOException, ServletException {
final HttpServletRequest request = (HttpServletRequest) req;
final HttpServletResponse response = (HttpServletResponse) res;
if (request.getMethod().equals(POST)) {
// If the incoming request is a POST, then we send it up
// to the AbstractAuthenticationProcessingFilter.
super.doFilter(request, response, chain);
} else {
// If it's a GET, we ignore this request and send it
// to the next filter in the chain. In this case, that
// pretty much means the request will hit the /login
// controller which will process the request to show the
// login page.
chain.doFilter(request, response);
}
}
...
}
Context xml:
<bean id="loginUrlAuthenticationEntryPoint" class="org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint">
<property name="loginFormUrl" value="/portalLogin.html"/>
</bean>
<bean id="MyFilter" class="com.infosys.itrade.core.dao.security.MyFilter">
<property name="authenticationManager" ref="authenticationManager"/>
<property name="authenticationSuccessHandler" ref="successHandler"></property>
<property name="authenticationFailureHandler" ref="failureHandler"></property>
<property name="filterProcessesUrl" value="/signIn"></property>
</bean>
<bean id="successHandler" class="org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler">
<property name="defaultTargetUrl" value="/welcome.html" />
</bean>
<bean id="failureHandler" class="org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler">
<property name="defaultFailureUrl" value="/loginfailed.html" />
</bean>
<security:authentication-manager alias="authenticationManager">
<security:authentication-provider
user-service-ref="LoginUserDetailsService">
</security:authentication-provider>
</security:authentication-manager>
<bean id="LoginUserDetailsService"
class="com.infy.itrade.core.service.login.LoginServiceImpl">
<property name="logindao" ref="loginDAOImpl" />
</bean>
<bean id="loginDAOImpl" class="com.infy.itrade.core.dao.login.LoginDAODBImpl">
<property name="sessionFactory"> <ref bean ="sessionFactory"/> </property>
</bean>
</beans>
What am i missing here?
[Update]: Since i couldn't get this working i changed my approach as suggested by others here i.e. I'm avoiding the architectural flow for login module alone. But right now i'm facing a different issue with the new approach for which i'll ask a different question. Thanks.

Resources