I am writing a form based OAUTH authentication for Getting The Authorization Code.It was supposed to have a "authorization decision Page" after the Resource Server asks the Resource Owner to authenticate itself and as for authorization to share data.
Below are the server side configs
Authorization Server
#Configuration
#EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
#Bean
public BCryptPasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
#Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory().withClient("javainuse").secret("{noop}secret").authorizedGrantTypes("authorization_code")
.scopes("read").authorities("CLIENT");
}
}
WebSecurity Configurer
#Configuration
#EnableWebSecurity
public class EmployeeSecurityConfiguration extends WebSecurityConfigurerAdapter {
#Bean
#Override
public AuthenticationManager authenticationManager() throws Exception {
return super.authenticationManager();
}
#Autowired
private BCryptPasswordEncoder passwordEncoder;
#Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/resources/**");
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().antMatchers("/").permitAll().antMatchers("/user/getEmployeesList")
.hasAnyRole("ADMIN").anyRequest().authenticated().and().formLogin()
.permitAll().and().logout().permitAll();
http.csrf().disable();
}
#Override
public void configure(AuthenticationManagerBuilder authenticationMgr) throws Exception {
authenticationMgr.inMemoryAuthentication().withUser("admin").password(passwordEncoder.encode("admin"))
.authorities("ROLE_ADMIN");
}
}
Below are the client side configs
Controller
#Controller
public class EmployeeController {
#RequestMapping(value = "/getEmployees", method = RequestMethod.GET)
public ModelAndView getEmployeeInfo() {
return new ModelAndView("getEmployees");
}
#RequestMapping(value = "/showEmployees", method = RequestMethod.GET)
public String getEmployeeInfo1() {
return "showEmployees";
}
}
getEmployees.jsp
<%#taglib uri="http://www.springframework.org/tags/form" prefix="form"%>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Add Employee</title>
</head>
<body>
<h3 style="color: red;">Add New Employee</h3>
<div id="addEmployee">
<form:form action="http://localhost:8081/oauth/authorize"
method="post" modelAttribute="emp">
<p>
<label>Enter Employee Id</label>
<input type="text" name="response_type" value="code" />
<input type="text" name="client_id" value="javainuse" />
<input type="text" name="redirect_uri" value="http://localhost:8090/showEmployees" />
<input type="text" name="scope" value="read" />
<input type="SUBMIT" value="Get Employee info" />
</form:form>
</div>
</body>
</html>
After providing login details on login prompt
i provided the details, after it should have provided me prompt at http://localhost:8081/oauth/authorize
it is giving me info on logs
INFO AuthorizationEndpoint : Handling OAuth2 error: error="invalid_request", error_description="At least one redirect_uri must be registered with the client."
any help is really appreciated, not sure where i'm doing wrong.
I'm using Spring Boot 2.0.2.RELEASE.
The redirect_uri value http://localhost:8090/showEmployees which is given in the input tag is also needs to be mapped in Authorization Server configuration above, so
#Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory().withClient("javainuse").secret("secret").authorizedGrantTypes("authorization_code")
.scopes("read").authorities("CLIENT").redirectUris("http://localhost:8090/showEmployees");
}
adding redirect URL in ClientDetailsServiceConfigurer will work.
Related
Here is login form
<html lang="en">
<head>
<meta charset="utf-8">
<title>Login Customer</title>
</head>
<body>
<div class="container">
<form class="form-signin" method="POST" action="/api/v1/auth/login">
<h2 class="form-signin-heading">Login</h2>
<p>
<label for="username">Username</label>
<input type="text" id="username" name="username" class="form-control" placeholder="Username" required>
</p>
<p>
<label for="password">Password</label>
<input type="password" id="password" name="password" class="form-control" placeholder="Password" required>
</p>
<button class="btn btn-lg btn-primary btn-block" type="submit">Sign in</button>
</form>
</div>
</body>
</html>
When user submit login form it sends data to authenticate method in #RestController.
#RestController
#RequestMapping("/api/v1/auth")
public class AuthenticationRestControllerV1 {
private final AuthenticationManager authenticationManager;
private final UserRepository userRepository;
private final JwtTokenProvider jwtTokenProvider;
public AuthenticationRestControllerV1(AuthenticationManager authenticationManager, UserRepository userRepository, JwtTokenProvider jwtTokenProvider) {
this.authenticationManager = authenticationManager;
this.userRepository = userRepository;
this.jwtTokenProvider = jwtTokenProvider;
}
#RequestMapping(value = "/login", method = RequestMethod.POST)
public #ResponseBody ResponseEntity<?> authenticate(#RequestParam(name="username") String username, #RequestParam(name = "password") String password, HttpServletResponse response){
try {
authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(username, password));
User user = userRepository.findByEmail(username).orElseThrow(() -> new UsernameNotFoundException("User doesn`t exist"));
String token = jwtTokenProvider.createToken(username, user.getRole().name());
Cookie cookie = new Cookie("Authorization", token);
cookie.setPath("/");
cookie.setHttpOnly(true);
response.addCookie(cookie);
return new ResponseEntity<>(new JwtResponse(username, token),HttpStatus.OK);
}catch (AuthenticationException exception){
return new ResponseEntity<>("Invalid email/password combination", HttpStatus.FORBIDDEN);
}
}
...
}
In SecurityConfig class method configure has successForwardUrl("/auth/success") which must redirect me to success page, but it doesn't. I also tried defaultSuccessUrl("/auth/success") and successHandler(successHandler). It just doesn`t work at all so it keeps me on authenticate method
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
private final JwtConfigurer jwtConfigurer;
private final JwtAuthenticationSuccessHandler successHandler;
public SecurityConfig(JwtConfigurer jwtConfigurer, JwtAuthenticationSuccessHandler successHandler) {
this.jwtConfigurer = jwtConfigurer;
this.successHandler = successHandler;
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
.antMatchers("/api/v1/auth/login").permitAll()
.antMatchers("/auth/login").permitAll()
.anyRequest().authenticated().and().apply(jwtConfigurer)
.and().formLogin().loginPage("/auth/login").permitAll().successForwardUrl("/auth/success");
}
#Bean
#Override
public AuthenticationManager authenticationManagerBean() throws Exception{
return super.authenticationManagerBean();
}
#Bean
protected PasswordEncoder passwordEncoder(){
return new BCryptPasswordEncoder(12);
}
}
Here is #Controller which I use for getting my login page and success page
#Controller
#RequestMapping("/auth")
public class AuthController {
#GetMapping("/login")
public String getLoginPage(){
return "login";
}
#GetMapping("/success")
public String getSuccessPage(){
return "success";
}
}
I'm trying to create a page that will hold some user data that may be accessed through some client webpage. That brought me to oauth2 (authorization code) and Spring. Currently I'm working on some kind of proof of concept for this basing my code on https://github.com/dynamind/spring-boot-security-oauth2-minimal/ and this workflow https://techannotation.files.wordpress.com/2015/06/oauth2-0-authorization-code.png
I already have a resource server that uses login page for authentication of users and then gives them a possibility of some kind of approval for sharing their data. Then it redirects user to a page set up for client.
#SpringBootApplication
public class AuthorizationServerApplication extends SpringBootServletInitializer {
private static final Logger log = LoggerFactory.getLogger(AuthorizationServerApplication.class);
public static void main(String[] args) {
ApplicationContext context = SpringApplication.run(AuthorizationServerApplication.class, args);
}
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(AuthorizationServerApplication.class);
}
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true)
protected static class SecurityConfig extends WebSecurityConfigurerAdapter {
#Override
#Autowired // <-- This is crucial otherwise Spring Boot creates its own
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
log.info("Defining inMemoryAuthentication (2 users)");
auth.inMemoryAuthentication()
.withUser("user").password("password").roles("USER")
.and()
.withUser("admin").password("password").roles("USER", "ADMIN");
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.formLogin()
.and()
.httpBasic().disable().anonymous().disable().authorizeRequests().anyRequest().authenticated();
}
}
#Configuration
#EnableAuthorizationServer
protected static class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
#Value("${config.oauth2.privateKey}")
private String privateKey;
#Value("${config.oauth2.publicKey}")
private String publicKey;
#Autowired
private AuthenticationManager authenticationManager;
#Bean
public JwtAccessTokenConverter tokenEnhancer() {
log.info("Initializing JWT with public key:\n" + publicKey);
JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
converter.setSigningKey(privateKey);
converter.setVerifierKey(publicKey);
return converter;
}
#Bean
public JwtTokenStore tokenStore() {
return new JwtTokenStore(tokenEnhancer());
}
/**
* Defines the security constraints on the token endpoints
* /oauth/token_key and /oauth/check_token Client credentials are
* required to access the endpoints
*
* #param oauthServer
* #throws Exception
*/
#Override
public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
oauthServer.tokenKeyAccess("isAnonymous() || hasRole('ROLE_TRUSTED_CLIENT')") // permitAll()
.checkTokenAccess("hasRole('TRUSTED_CLIENT')"); // isAuthenticated()
}
/**
* Defines the authorization and token endpoints and the token services
*
* #param endpoints
* #throws Exception
*/
#Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints
// Which authenticationManager should be used for the
// password grant
// If not provided, ResourceOwnerPasswordTokenGranter is not
// configured
.authenticationManager(authenticationManager)
// Use JwtTokenStore and our jwtAccessTokenConverter
.tokenStore(tokenStore()).accessTokenConverter(tokenEnhancer());
}
#Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
// Public client where client secret is vulnerable (e.g.
// mobile apps, browsers)
.withClient("clientname") // No secret!
.authorizedGrantTypes("authorization_code").scopes("read")
.redirectUris("http://localhost:8080/client")
;
}
}
}
Currently I'm dealing with a simplest possible client webpage. I created a page with link to authorization server (localhost:8081/oauth/authorize...). User clicks on it and is redirected to authorization server, logs in there, approves sharing his/hers data and is then redirected back to client site (localhost:8080/client but with code given by authorization server), but now with additional option to click one more link (localhost:8081/oauth/token...) that has returned code in it. All this works, but when user clicks this second link and is redirected to authorization server, this auth server responds with "Full authentication is required to access this resource".
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>client page</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>
<p th:text="'oooo text oooo'" />
if you want it
<a
th:href="#{http://localhost:8081/oauth/authorize(response_type='code',client_id='client',key='value',scope='read',redirect_uri='http://localhost:8080/client')}">clickit</a>
<a th:if="${param.code != null}"
th:href="#{http://localhost:8081/oauth/token(grant_type='authorization_code',code=${param.code[0]},redirect_uri='http://localhost:8080/client')}">
approve
</a>
<div th:if=" ${param.code !=null}
"
th:text="${'requestParam: ' + param.code[0]}"></div>
</body>
</html>
Do you have any ideas for this problem?
Turns out it was because I didn't use POST request. Using this solved the problem:
<form th:if="${param.code != null}"
th:method="post"
th:action="#{http://localhost:8081/oauth/token}">
<input type="text" id="grant_type" name="grant_type" th:value="authorization_code"/>
<input type="text" id="client_id" name="client_id" th:value="client"/>
<input type="text" id="code" name="code" th:value="${param.code[0]}"/>
<input type="text" id="redirect_uri" name="redirect_uri" th:value="#{http://localhost:8080/client}"/>
<input type="submit" />
</form>
I want to check captcha if use wants to be logined and if captcha was correct, call filterChain.doFilter() to resume authentication and if captcha was incorrect rediredt user to login page to re-enter username, password and captcha.
So, i want to put my CaptchaFilter with /login filterMapping in the first of spring securtiy fiter chain.
login.jsp
<%# taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%# page contentType="text/html; charset=UTF-8" language="java" pageEncoding="UTF-8" session="true" %>
<html>
<head>
<title>Login Page</title>
</head>
<body onload='document.loginForm.username.focus();'>
<div id="login-box">
<form name='loginForm' action="<c:url value='/login' />" method='POST'>
<table>
<tr>
<td>User:</td>
<td><input type='text' name='username'></td>
</tr>
<tr>
<td>Password:</td>
<td><input type='password' name='password'/>
</td>
</tr>
<tr>
<td colspan="2">
<img id="imgCaptcha" src="<c:url value = '/j-captcha.jpg' />" onclick='this.src="<c:url value='/j-captcha.jpg'/>";' style="cursor: pointer"/>
</td>
</tr>
<tr>
<td colspan="2">
<input name="jcaptcha" type="text" placeholder="captcha"/>
</td>
<tr>
<td colspan='2'><input name="submit" type="submit" value="submit"/></td>
</tr>
</table>
</form>
</div>
</body>
</html>
CaptchaFilter
public class CaptchaFilter implements Filter {
#Override
public void init(FilterConfig filterConfig) throws ServletException {
}
#Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) servletRequest;
HttpServletResponse response = (HttpServletResponse) servletResponse;
if (request.getParameter("jcaptcha") != null) {
checkCaptcha(request, response, filterChain);
} else {
filterChain.doFilter(request, response);
}
}
private void checkCaptcha(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws IOException, ServletException {
try {
String userCaptchaResponse = request.getParameter("jcaptcha");
boolean isResponseCorrect = CaptchaService.getInstance().validateResponseForID(request.getRequestedSessionId(), userCaptchaResponse);
if (isResponseCorrect) {
filterChain.doFilter(request, response);
} else {
String url = request.getHeader("referer").replaceAll("[&?]error.*?(?=&|\\?|$)", "");
url += "?error=" + SecurityUtility.CAPTCHA_IS_WRONG;
redirect(request, response, url);
}
} catch (Exception e) {
e.printStackTrace();
filterChain.doFilter(request, response);
}
}
private void redirect(HttpServletRequest request, HttpServletResponse response, String url) {
try {
response.sendRedirect(request.getContextPath() + url);
} catch (Exception ex) {
ex.printStackTrace();
}
}
#Override
public void destroy() {
}
}
SpringSecurityConfig:
#Configuration
#EnableWebSecurity
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
#Qualifier("userDetailsService")
UserDetailsService userDetailsService;
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService);
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().antMatchers("/admin/**")
.access("hasRole('ROLE_USER')").and().formLogin()
.loginPage("/login").failureUrl("/login?error")
.usernameParameter("username")
.passwordParameter("password")
.and().logout().logoutSuccessUrl("/login?logout")
.and().exceptionHandling().accessDeniedPage("/403");
}
}
SpringWebConfig
#EnableWebMvc
#Configuration
#ComponentScan({"com.rgh.*"})
#EnableTransactionManagement
#Import({SpringSecurityConfig.class})
public class SpringWebConfig {
#Bean
public SessionFactory sessionFactory() {
LocalSessionFactoryBuilder builder = new LocalSessionFactoryBuilder(dataSource());
builder.scanPackages("com.rgh.*.model").addProperties(getHibernateProperties());
return builder.buildSessionFactory();
}
private Properties getHibernateProperties() {
// set and return properties
}
#Bean(name = "dataSource")
public BasicDataSource dataSource() {
// set and return datasource
}
#Bean
public HibernateTransactionManager txManager() {
return new HibernateTransactionManager(sessionFactory());
}
}
SpringWebInitializer
public class SpringWebInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
#Override
protected Class<?>[] getRootConfigClasses() {
return new Class[]{SpringWebConfig.class};
}
#Override
protected String[] getServletMappings() {
return new String[]{"/", "/rest/*"};
}
}
SpringSecurityInitializer
public class SpringSecurityInitializer extends AbstractSecurityWebApplicationInitializer {
}
i'm new to spring 4 and spring java config.
You can add your filter like this :
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
...
http.addFilterAfter(yourFilter, CsrfFilter.class);
...
}
There are other methods addFilterBefore(..) and addFilter(..) to add filters.
addFilterBefore and addFilterAfter expect as second argument a filter class that is part of the SecurityFilterChain, and they will be added relative to it.
addFilter requires some comperator which I never tried.
To find the filter classes that are actually in the SecurityFilterChain set a breakpoint in a controller method and search in the stack for the SecurityFilterChain (or DefaultSecurityFilterChain). There you can see which filter classes are configured e.g. in DefaultSecurityFilterChain.fiters
Find the first filter class than use addFilterBefore to add your CaptchaFilter.
I am implementing spring security using the java configuration.
Poviding the necessary config classes here.
SpringSecurity.java
#Configuration
#EnableWebSecurity
public class SpringSecurity extends WebSecurityConfigurerAdapter {
#Autowired
private AuthenticationSuccessHandler authenticationSuccessHandler;
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth)
throws Exception {
auth.inMemoryAuthentication().withUser("user").password("password").roles("IS_AUTHENTICATED_ANONYMOUSLY");
}
#Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/resources/**");
}
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable().authorizeRequests().antMatchers("/auth/login").permitAll()
.anyRequest().authenticated()
.and().formLogin().loginPage("/auth/login")
.usernameParameter("j_username").passwordParameter("j_password")
.permitAll().successHandler(authenticationSuccessHandler)
.and().httpBasic();
}
}
WebConfig.java
public class WebConfig extends AbstractAnnotationConfigDispatcherServletInitializer{
#Override
protected Class<?>[] getRootConfigClasses() {
return new Class[] { SpringConfig.class,SpringSecurity.class };
}
#Override
protected Class<?>[] getServletConfigClasses() {
// TODO Auto-generated method stub
return null;
}
#Override
protected String[] getServletMappings() {
// TODO Auto-generated method stub
return new String[] {"/"};
}
}
AuthenticationSuccessHandler.java
#Component
public class AuthenticationSuccessHandler implements org.springframework.security.web.authentication.AuthenticationSuccessHandler{
private RedirectStrategy redirectStrategy = new DefaultRedirectStrategy();
#Override
public void onAuthenticationSuccess(HttpServletRequest request,
HttpServletResponse response, Authentication authentication) throws IOException,
ServletException {
System.out.println(authentication.getName());
redirectStrategy.sendRedirect(request, response, "/home/homePage");
}
}
SpringConfig.java is where all the datasource and other packages scan related stuff are defined, i guess that won't be needed here.
Problem is that when hit the login page url (contextPath)/auth/login, it shows me login page. But,
after i hit the login button it redirects me to the same login page.
I am providing the login.jsp here.
<form:form action="../home/homePage" class = "form-horizontal">
<legend id = "loginLegend">LOGIN</legend>
<hr style="border: none; height: 1px; color: blue; background: #244363;"/>
UserName: <br>
<input type="text" class="form-control" name="j_username" style = "width: 90% !important; margin-left : 20px;"/><br>
Password:<br>
<input type="password" class = "form-control" name="j_password" style = "width: 90% !important;margin-left : 20px;"/><br>
<button id = "loginButton" class="btn btn-primary" type="submit">Login</button>
</form:form>
So a few issues with what you have now and how you are expecting it to work.
Firstly, you need to point your login page to the url that will process the login form (you can have custom if you want).
Secondly, if you want the user to always end up at "/home/homePage" then you should just add loginSuccessURL("/home/homePage");
Otherwise what you can do, is just set the antMatcher("/home/homePage") with a role expected and it will always request login unless the user is authenticated.
Create a login page
<%# taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="ISO-8859-1">
<title>Test</title>
<script src="static/js/jquery-1.10.2.min.js"></script>
<script src="static/js/app-controller.js"></script>
</head>
<body>
<div>Login</div>
<form name="f" action="<c:url value="/j_spring_security_check"/>" method="POST">
<label for="password">Username</label> <input type="text" id="j_username" name="j_username"><br/>
<label for="password">Password</label> <input type="password" id="j_password" name="j_password"><br/>
<input type="submit" value="Validate"> <input name="reset" type="reset">
<input type="hidden" id="${_csrf.parameterName}" name="${_csrf.parameterName}" value="${_csrf.token}"/>
</form>
<hr/>
<c:if test="${param.error != null}">
<div>
Failed to login.
<c:if test="${SPRING_SECURITY_LAST_EXCEPTION != null}">
Reason: <c:out value="${SPRING_SECURITY_LAST_EXCEPTION.message}" />
</c:if>
</div>
</c:if>
<hr/>
<input type="button" value="Echo" id="echo" name="echo" onclick="AppController.echo();">
<div id="echoContainer"></div>
</body>
</html>
Declare a WebSecurityConfigurer HERE IS WHERE I WAS MISSING j_username AND j_password
#Configuration
#EnableWebSecurity
#ComponentScan(basePackages = {"com.sample.init.security"})
public class WebSecurityConfigurer extends WebSecurityConfigurerAdapter {
#Inject
private AuthenticationProvider authenticationProvider;
#Inject
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(authenticationProvider);
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers(
"/resources/**",
"/static/**",
"/j_spring_security_check",
"/AppController/echo.html").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.usernameParameter("j_username") /* BY DEFAULT IS username!!! */
.passwordParameter("j_password") /* BY DEFAULT IS password!!! */
.loginProcessingUrl("/j_spring_security_check")
.loginPage("/")
.defaultSuccessUrl("/page")
.permitAll()
.and()
.logout()
.permitAll();
}
#Override
public void configure(WebSecurity web) throws Exception {
web
.ignoring()
.antMatchers("/static/**");
}
}
Declare a WebMvcConfigurer
#EnableWebMvc
#Configuration
#ComponentScan(basePackages = {
"com.app.controller",
"com.app.service",
"com.app.dao"
})
public class WebMvcConfigurer extends WebMvcConfigurerAdapter {
#Bean
public ViewResolver viewResolver() {
InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
viewResolver.setPrefix("/WEB-INF/view/");
viewResolver.setSuffix(".jsp");
return viewResolver;
}
#Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/page").setViewName("page");
}
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("static/**").addResourceLocations("static/");
}
}
Declare a Security Initializer
public class SecurityWebAppInitializer
extends AbstractSecurityWebApplicationInitializer { }
Declare an App Initialzer
public class Initializer extends AbstractAnnotationConfigDispatcherServletInitializer {
#Override
protected Class<?>[] getRootConfigClasses() {
return new Class<?>[]{WebSecurityConfigurer.class};
}
#Override
protected Class<?>[] getServletConfigClasses() {
return new Class<?>[]{WebMvcConfigurer.class, DataSourceConfigurer.class};
}
#Override
protected String[] getServletMappings() {
return new String[]{"/"};
}
}
Implement your custom Authentication Provider
#Component
#ComponentScan(basePackages = {"com.app.service"})
public class CustomAuthenticationProvider implements AuthenticationProvider {
private static final Logger LOG = LoggerFactory.getLogger(CustomAuthenticationProvider.class);
#Inject
private AppService service;
#Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
//Thread.dumpStack();
String username = authentication.getName();
String password = authentication.getCredentials().toString();
String message = String.format("Username: '%s' Password: '%s'", username, password);
UserBean userBean = service.validate(username, password);
LOG.debug(message);
if (userBean != null) {
List<GrantedAuthority> grantedAuths = new ArrayList<>();
grantedAuths.add(new SimpleGrantedAuthority("USER"));
return new UsernamePasswordAuthenticationToken(userBean, authentication, grantedAuths);
} else {
String error = String.format("Invalid credentials [%s]", message);
throw new BadCredentialsException(error);
}
}
#Override
public boolean supports(Class<?> authentication) {
return authentication.equals(UsernamePasswordAuthenticationToken.class);
}
}
I am skipping EchoController, AppService, AppDao and UserBean.
Thanks.
In 3.2 version post parameters have changed from j_username to username and j_password to password. The login url has also changed from /j_spring_security_check to /login.
See this link for the explanation of why this change was implemented: http://docs.spring.io/spring-security/site/docs/3.2.0.RELEASE/reference/htmlsingle/#jc-httpsecurity. These are the changes:
GET /login renders the login page instead of /spring_security_login
POST /login authenticates the user instead of /j_spring_security_check
The username parameter defaults to username instead of j_username
The password parameter defaults to password instead of j_password
And this for an example of a login form: http://docs.spring.io/spring-security/site/docs/3.2.0.RELEASE/reference/htmlsingle/#jc-form