Custom login page in Spring Security 5 using oauth2 returns null - spring

I am developing custom login page in Spring Security 5 using oauth2. So I have customized settings:
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests().antMatchers("/").permitAll()
.anyRequest().authenticated()
.and()
.oauth2Login().loginPage("/login/oauth2").permitAll();
}
and creating controller with #RequestMapping("/login/oauth2"):
#GetMapping("/")
public String index() {
return "index";
}
#GetMapping("/login/oauth2")
public String login(Model model, OAuth2AuthenticationToken authentication) {
return "login";
}
The login.html page is a regular form which redirect to login method from controller:
<h1>Logowanie</h1>
<a>ZALOGUJ</a>
<a class="btn" href="/login/oauth2/code/google">Login</a>
With this configuration OAuth2AuthenticationToken authentication is null and therefore authentication can't be applied. With default Spring Security 5 configuration everything works fine. The example on which I based is described here: https://docs.spring.io/spring-security/site/docs/5.0.0.RELEASE/reference/htmlsingle/#oauth2login-advanced-login-page; section 31.1 OAuth 2.0 Login Page.

In my app to work I had to create my custom WebMvc configuration:
#Configuration
public class WebMvcConfiguration implements WebMvcConfigurer {
#Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/login").setViewName("login");
registry.setOrder(Ordered.HIGHEST_PRECEDENCE);
}
}
Then in WebSecurityConfig:
#Override
protected void configure(final HttpSecurity http) throws Exception {
http.authorizeRequests().antMatchers("/login").permitAll()
.anyRequest().authenticated()
.and().formLogin()
.loginPage("/login")
.permitAll()
.and().csrf().disable()
.logout().permitAll();
}
I think in this case You don't need custom controller.
I wrote a blog post about silent token refresh in implicit flow, but there You will find full working app with custom login page:
https://regulargeek.blogspot.com/2018/05/angular-5-springboot-2-oauth2-and.html

Related

Spring Security redirecting custom login page to itself - Too Many Redirects

I'm currently developing a custom login-page for my Spring Boot Application but I just can't get it to work. Using the default one works fine but as soon as I try to use my custom file, it just repeatedly redirects me until my Browser give up.
Other posts suggest permitting access to the login-path to erveryone but this also doesn't seem to work.
Here is my code:
WebSecurityConfig
#Configuration
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.and()
.formLogin()
.loginPage("/login")
.permitAll()
.and()
.logout()
.permitAll();
}
}
And Controller for login-page
#Controller
public class WebController {
#GetMapping("/login")
public String login () {
return "login";
}
}
Any ideas what I'm missing?
You are probably using a lot of CSS and JS file link links, according to your code Spring Boot must first authenticate all the links, which is why it redirects to your login page many times.
add following code to bypass security authentication of resource link
public void configure(WebSecurity web) {
web.ignoring()
.antMatchers("/bower_components/**", "/dist/**", "/plugins/**"); //write your resource directory name
}

Spring Boot 2 Security downloading font file upon login

I've setup a spring boot 2 application with a login form, however, when you login, instead of redirecting to /admin like it's supposed to, it downloads a font file referenced by the stylesheet via an #import.
Here is my security setup;
#Configuration
#EnableWebSecurity()
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
UserService userService;
#Bean
public PasswordEncoder passwordEncoder() {
return PasswordEncoderFactories.createDelegatingPasswordEncoder();
}
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userService).passwordEncoder(passwordEncoder());
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable();
// These pages don't require the user to be logged in
http.authorizeRequests()
.antMatchers("/", "/login", "/logout", "/report/**").permitAll()
.requestMatchers(PathRequest.toStaticResources().atCommonLocations()).permitAll()
.anyRequest().authenticated();
// When the user has logged in as XX.
// But access a page that requires role YY,
// AccessDeniedException will be thrown.
http.authorizeRequests().and().exceptionHandling().accessDeniedPage("/403");
// Config for Login Form
http.authorizeRequests().and().formLogin()//
// Submit URL of login page.
.loginProcessingUrl("/j_spring_security_check") // Submit URL
.loginPage("/login")//
.defaultSuccessUrl("/admin")//
.failureUrl("/login?error=true")//
.usernameParameter("username")//
.passwordParameter("password")
// Config for Logout Page
.and().logout().logoutUrl("/logout").logoutSuccessUrl("/login?logout=true");
}
}
Where am I going wrong? From what I can see, I'm enabling access to Spring resources that are stored in the static folder.
I figured this one out, I read the code that allows access to resources and noticed it said 'atCommonLocations', and guess this adds access to folders such as css, js, img, images etc. I had fonts in a folder labelled webfonts, so I updated my security configuration;
http.authorizeRequests()
.antMatchers("/", "/login", "/logout", "/report/**", "/webfonts/**").permitAll()
.requestMatchers(PathRequest.toStaticResources().atCommonLocations()).permitAll()
.anyRequest().authenticated();

Spring Boot: Authenticating both a Stateless REST API and a Stateful "Login" Web Controller in the same project?

So I have an application that contains a REST API which is used by a custom java application on an IOT device with no user interaction.And I also have a web app which needs a stateful session for maintaining user login.
Is it possible to use Spring Security to authenticate requests to my API and web controller differently?What form of authentication should I be using for the REST API?
One way to achieve what you are looking for is to have 2 configurations in your spring security. E.g.
Pay attention to antMatcher (matcher not matchers). The antMatcher will control on what set of url your entire config applies i.e. FormLoginWebSecurityConfigurerAdapter in below example will apply only to uri matching /api/test/**. Of course, you can define the antMatcher only in one of the configs say config1 and the other config in that case will be a catch all (i.e catch everything that does not match config1)
#EnableWebSecurity
#Configuration
public class SecurityConfig {
#Configuration
#Order(1)
public static class ApiWebSecurityConfigurationAdapter extends WebSecurityConfigurerAdapter {
#Override
public void configure(AuthenticationManagerBuilder auth)
throws Exception {
auth.inMemoryAuthentication().withUser("user").password("user").roles("USER");
auth.inMemoryAuthentication().withUser("admin").password("admin").roles("ADMIN");
}
protected void configure(HttpSecurity http) throws Exception {
http.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
http
.antMatcher("/api/v1/**")
.authorizeRequests()
.antMatchers("/api/v1/**").authenticated()
.and()
.httpBasic();
}
}
#Configuration
#Order(2)
public static class FormLoginWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {
#Override
public void configure(AuthenticationManagerBuilder auth)
throws Exception {
auth.inMemoryAuthentication().withUser("user1").password("user").roles("USER");
auth.inMemoryAuthentication().withUser("admin1").password("admin").roles("ADMIN");
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED); // CONFIGURE TYPE OF SESSION POLICY
http
.antMatcher("/api/test/**")
.authorizeRequests()
.antMatchers("/api/test/**").authenticated()
.and()
.formLogin();
}
}
}

Unauthorized error when using Spring Security and Angular

My frontend is based on Angular 4 and my backend is based on Spring Boot with Spring Security.
I am deploying everything in a single WAR file.
I created a static/landing folder in /src/main/resources and then I put the Webpack-built Angular files in that folder.
Angular is taking care of the login process and so I created the following rule in Spring Security :
#Configuration
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Bean
public WebMvcConfigurerAdapter mappingIndex() {
return new WebMvcConfigurerAdapter() {
#Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/login").setViewName("forward:/landing/index.html");
}
};
}
#Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
.addFilterBefore(new CORSFilter(),ChannelProcessingFilter.class)
.antMatchers(/"login/**").permitAll()
.anyRequest().authenticated();
Unfortunately, I am always getting the HTTP Status code 401 (Unauthorized) when trying to access the /login page with the webbrowser for signing in.
How can I achieve to integrate the Angular App in this way ? Because my Security rules are working fine with the REST Apis.
.antMatchers(/"login/**").permitAll() looks wrong,
try this:
#Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
httpSecurity
.authorizeRequests()
.antMatchers("/login/**").permitAll()
.anyRequest().authenticated();
}
if it still doesn't work, add to your application.properties
logging.level.org.springframework.security=trace
logging.level.org.springframework.web=trace
and post output

Spring Security "Remember Me" redirection to login

I'm trying to implement remember me functionallity in my webapp with Spring Security. The cookie is established correctly (I've seen it in browser) and recognized by the server (my app finds the user in bbdd) but always I am being redirected to login page. Does Anybody can help me?
My Security configuration is:
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
#Autowired
CustomAuthenticationProvider customAuthenticationProvider;
RememberMeAuthenticationProvider rememberMeAuthenticationProvider = new RememberMeAuthenticationProvider(
"OTRS_KEY");
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth)
throws Exception {
auth.authenticationProvider(customAuthenticationProvider);
}
#Override
public void configure(WebSecurity web) throws Exception {
web.debug(true)
.ignoring()
.antMatchers("/unsec/**", "/resources/**", "/css/**",
"/images/**", "/design/**", "/javax.faces.resource/**",
"/syntaxhighlighter/**");
}
/*
* JSF 1.2/2.0/2.1/2.2 has implicit CSRF protection when h:form is submitted
* with a POST request. This is because the javax.faces.ViewState hidden
* field contains a sufficiently random token. JSF 2.2 adds CSRF protection
* to HTTP GET by allowing the developer to specify protected-views in the
* WEB-INF/faces-config.xml descriptor. URLs that invoke the JSF lifecycle
* via HTTP GET must have the new javax.faces.Token URL parameter. For more
* information, see the tutorial titled Java EE 7: Implementing CSRF
* Protection with JSF 2.2.
*/
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable().headers().frameOptions().disable().formLogin()
.loginProcessingUrl("/j_spring_security_check")
.usernameParameter("j_username")
.passwordParameter("j_password")
.loginPage("/unsec/secureLogin.jsf")
.defaultSuccessUrl("/sec/home.jsf")
.failureUrl("/unsec/secureLogin.jsf").and().rememberMe()
.rememberMeServices(tokenBasedRememberMeServices()).and()
.authorizeRequests().antMatchers("/unsec/**").permitAll()
.antMatchers("/sec/**").authenticated().and().logout()
.deleteCookies("JSESSIONID", "OTRS_REMEMBER");
}
#Bean
public PasswordEncoder passwordEncoder() {
// return new BCryptPasswordEncoder();
return NoOpPasswordEncoder.getInstance();
}
private TokenBasedRememberMeServices tokenBasedRememberMeServices() {
TokenBasedRememberMeServices t = new TokenBasedRememberMeServices(
"OTRS_KEY", satecAuthenticationProvider.getIdentitiesService());
t.setParameter("_spring_security_remember_me_input");
t.setAlwaysRemember(true);
t.setCookieName("OTRS_REMEMBER");
t.setTokenValiditySeconds(7200);
return t;
}
}

Resources