From a9a2c587a4de11ce04aaae7a0c1a5dab1430794a Mon Sep 17 00:00:00 2001 From: Alexander Alexeev Date: Wed, 5 Apr 2017 17:36:38 +0700 Subject: login by hash, remember-me --- .../security/HashParamAuthenticationFilter.java | 66 ++++++++++++++++++++++ .../java/com/juick/service/UserServiceImpl.java | 5 +- .../juick/www/configuration/WebSecurityConfig.java | 41 ++++++++++---- .../main/java/com/juick/www/controllers/Login.java | 40 +++---------- 4 files changed, 107 insertions(+), 45 deletions(-) create mode 100644 juick-server/src/main/java/com/juick/server/security/HashParamAuthenticationFilter.java diff --git a/juick-server/src/main/java/com/juick/server/security/HashParamAuthenticationFilter.java b/juick-server/src/main/java/com/juick/server/security/HashParamAuthenticationFilter.java new file mode 100644 index 00000000..df1ae38c --- /dev/null +++ b/juick-server/src/main/java/com/juick/server/security/HashParamAuthenticationFilter.java @@ -0,0 +1,66 @@ +package com.juick.server.security; + +import com.juick.User; +import com.juick.server.security.entities.JuickUser; +import com.juick.service.UserService; +import org.springframework.security.authentication.AnonymousAuthenticationToken; +import org.springframework.security.authentication.RememberMeAuthenticationToken; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; +import org.springframework.web.filter.OncePerRequestFilter; + +import javax.servlet.FilterChain; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + +/** + * Created by aalexeev on 4/5/17. + */ +public class HashParamAuthenticationFilter extends OncePerRequestFilter { + public static final String PARAM_NAME = "hash"; + + private final UserService userService; + + + public HashParamAuthenticationFilter(UserService userService) { + this.userService = userService; + } + + @Override + protected void doFilterInternal( + HttpServletRequest request, + HttpServletResponse response, + FilterChain filterChain) throws ServletException, IOException { + + String hash = request.getHeader(PARAM_NAME); + + if (hash == null) + hash = request.getParameter(PARAM_NAME); + + if (hash != null && authenticationIsRequired()) { + User user = userService.getUserByHash(hash); + + if (!user.isAnonymous()) + SecurityContextHolder.getContext().setAuthentication( + new RememberMeAuthenticationToken(hash, new JuickUser(user), JuickUser.USER_AUTHORITY)); + } + + filterChain.doFilter(request, response); + } + + private boolean authenticationIsRequired() { + Authentication existingAuth = SecurityContextHolder.getContext().getAuthentication(); + + if (existingAuth == null || !existingAuth.isAuthenticated()) + return true; + + if (existingAuth instanceof AnonymousAuthenticationToken) + return true; + + return false; + } +} diff --git a/juick-server/src/main/java/com/juick/service/UserServiceImpl.java b/juick-server/src/main/java/com/juick/service/UserServiceImpl.java index 81a1fea7..1b33a6d3 100644 --- a/juick-server/src/main/java/com/juick/service/UserServiceImpl.java +++ b/juick-server/src/main/java/com/juick/service/UserServiceImpl.java @@ -4,6 +4,7 @@ import com.juick.User; import com.juick.server.helpers.Auth; import com.juick.server.helpers.EmailOpts; import com.juick.server.helpers.UserInfo; +import com.juick.server.security.entities.AnonymousUser; import com.juick.util.UserUtils; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.StringUtils; @@ -126,7 +127,7 @@ public class UserServiceImpl extends BaseJdbcService implements UserService { return list.get(0); } // TODO: @NonNullable ? - return new User(); + return AnonymousUser.INSTANCE; } @Override @@ -284,7 +285,7 @@ public class UserServiceImpl extends BaseJdbcService implements UserService { return user; } } - return new User(); + return AnonymousUser.INSTANCE; } @Transactional diff --git a/juick-www/src/main/java/com/juick/www/configuration/WebSecurityConfig.java b/juick-www/src/main/java/com/juick/www/configuration/WebSecurityConfig.java index 2b8dc292..3c674d0c 100644 --- a/juick-www/src/main/java/com/juick/www/configuration/WebSecurityConfig.java +++ b/juick-www/src/main/java/com/juick/www/configuration/WebSecurityConfig.java @@ -1,17 +1,20 @@ package com.juick.www.configuration; +import com.juick.server.security.HashParamAuthenticationFilter; import com.juick.server.security.entities.JuickUser; import com.juick.service.UserService; import com.juick.service.security.JuickUserDetailsService; -import com.juick.service.security.deprecated.RequestParamHashRememberMeServices; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; +import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.authentication.dao.DaoAuthenticationProvider; +import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.builders.WebSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.core.userdetails.UserDetailsService; -import org.springframework.security.web.authentication.RememberMeServices; +import org.springframework.security.web.authentication.www.BasicAuthenticationFilter; import javax.annotation.Resource; @@ -33,8 +36,15 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter { return new JuickUserDetailsService(userService); } + @Bean("authenticationManager") + @Override + public AuthenticationManager authenticationManagerBean() throws Exception { + return super.authenticationManagerBean(); + } + @Override protected void configure(HttpSecurity http) throws Exception { + http.addFilterAfter(hashParamAuthenticationFilter(), BasicAuthenticationFilter.class); http .authorizeRequests() .antMatchers("/settings", "/pm/**").authenticated() @@ -44,7 +54,7 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter { .and() .sessionManagement().invalidSessionUrl("/") .and() - .logout().invalidateHttpSession(true).logoutUrl("/logout").logoutSuccessUrl("/") + .logout().invalidateHttpSession(true).logoutUrl("/logout").logoutSuccessUrl("/login?logout") .and() .formLogin() .loginPage("/login") @@ -53,30 +63,37 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter { .loginProcessingUrl("/login") .usernameParameter("username") .passwordParameter("password") - .failureUrl("/login-error") + .failureUrl("/login?error=1") .and() .rememberMe() .tokenValiditySeconds(6 * 30 * 24 * 3600) .alwaysRemember(true) //.useSecureCookie(true) // TODO Enable if https is supports - .rememberMeCookieDomain(webDomain) + .rememberMeCookieDomain(webDomain).key(rememberMeKey) .userDetailsService(userDetailsServiceBean()) - .rememberMeServices(rememberMeServices()) - .key(rememberMeKey) - .and().authenticationProvider(authenticationProvider()) + .and() + .csrf().disable() + .authenticationProvider(authenticationProvider()) .headers().defaultsDisabled().cacheControl(); } + @Bean - public DaoAuthenticationProvider authenticationProvider() { + public DaoAuthenticationProvider authenticationProvider() throws Exception { DaoAuthenticationProvider authenticationProvider = new DaoAuthenticationProvider(); - authenticationProvider.setUserDetailsService(userDetailsService()); + authenticationProvider.setUserDetailsService(userDetailsServiceBean()); return authenticationProvider; } @Bean - public RememberMeServices rememberMeServices() throws Exception { - return new RequestParamHashRememberMeServices(rememberMeKey, userService); + public HashParamAuthenticationFilter hashParamAuthenticationFilter() { + return new HashParamAuthenticationFilter(userService); + } + + @Override + public void configure(WebSecurity web) throws Exception { + web.debug(false); + web.ignoring().antMatchers("/style.css*", "/scripts.js*"); } } diff --git a/juick-www/src/main/java/com/juick/www/controllers/Login.java b/juick-www/src/main/java/com/juick/www/controllers/Login.java index a83cbc16..8f9a993a 100644 --- a/juick-www/src/main/java/com/juick/www/controllers/Login.java +++ b/juick-www/src/main/java/com/juick/www/controllers/Login.java @@ -19,47 +19,25 @@ package com.juick.www.controllers; import com.juick.service.UserService; import com.juick.util.UserUtils; -import com.juick.www.Utils; -import com.juick.www.WebApp; -import org.springframework.security.core.Authentication; -import org.springframework.security.core.context.SecurityContextHolder; -import org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestMethod; - -import javax.inject.Inject; -import javax.servlet.http.Cookie; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import java.io.IOException; -import java.io.PrintWriter; +import org.springframework.web.bind.annotation.GetMapping; /** - * * @author Ugnich Anton */ @Controller public class Login { - @Inject - UserService userService; - @Inject - WebApp webApp; + @Autowired + private UserService userService; - @RequestMapping(value = "/login", method = RequestMethod.GET) - protected String doGetLoginForm(HttpServletRequest request, HttpServletResponse response) throws IOException { + @GetMapping("/login") + public String getloginForm() { com.juick.User visitor = UserUtils.getCurrentUser(); - if (!visitor.isAnonymous()) { + + if (!visitor.isAnonymous()) return "redirect:/"; - } + return "views/login"; } - @RequestMapping(value="/logout", method = RequestMethod.GET) - public String logoutPage (HttpServletRequest request, HttpServletResponse response) { - Authentication auth = SecurityContextHolder.getContext().getAuthentication(); - if (auth != null){ - new SecurityContextLogoutHandler().logout(request, response, auth); - } - return "redirect:/login?logout"; - } } -- cgit v1.2.3