Spring PKCE flow with custom login page - spring-boot

Hi I have a spring application using PKCE flow, I want to use custom login page in angular application (actually I use defaul login page spring app), follow my configuration in spring:
#Bean
public SecurityFilterChain resourcedefaultSecurityFilterChain(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/categorias").permitAll()
.anyRequest().authenticated()
.and()
.csrf().disable()
.oauth2ResourceServer().jwt().jwtAuthenticationConverter(jwtAuthenticationConverter());
http.logout(logoutConfig -> logoutConfig.logoutSuccessHandler((request, response, auth) -> {
var returnTo = request.getParameter("returnTo");
if (StringUtils.isBlank(returnTo)){
returnTo = algamoneyApiProperty.getSeguranca().getAuthServerUrl();
}
response.setStatus(FOUND);
response.sendRedirect(returnTo);
}));
return http.formLogin(Customizer.withDefaults()).build();// I want disable this config and use my login form in front-en
}
I have a question about this:
I my login page what endpoint I need to send a user credentials for spring app ? '/login', 'oauth2/login' and how params I need to use in this request?
I use spring-authorization-server in 0.3.1 version

Related

I am not being able to implement JWT token on a server side spring boot app

I have created a MVC spring boot app, mapping with a mySQL table, configured security to allow admin to access list of students and users are able to access list of subjects. Till this point everything is working fine.
Now i wanna put into play the JWT token. The problem is every video i follow use the JWT with post man and with simple #RestControllers but no MVC.
When i try to access 1 of the lists after starting the server, the custom login page comes to play and i enter details and everything works fine.
But, how do I implement the token? I have created a no MVC endpoint named "/authenticate" which returns me a token and using post man it works fine. But how do i return it in the app when i try to login using custom login page? Im not getting smthng here. Any help is appriciated. Thanks in advance!
Here is the endpoint for authenticate using postman:
#PostMapping ("/authenticate")
public ResponseEntity<?> createAuthenticationToken(#RequestBody AuthenticationRequest authenticationRequest) throws Exception {
try {
authenticationManager.authenticate(
new UsernamePasswordAuthenticationToken(
authenticationRequest.getUsername(), authenticationRequest.getPassword()));
} catch (BadCredentialsException e)
{
throw new Exception("Incorrect UserName or Password!",e);
}
UserDetails userDetails =
customUserDetailsService.loadUserByUsername(authenticationRequest.getUsername());
String jwt = jwtUtil.generateToken(userDetails);
return ResponseEntity.ok(new AuthenticationResponse(jwt));
}
Here is my security configuration :
http.
csrf().disable()
.authorizeRequests()
.antMatchers("/","/registration/","/logout","/login","/authenticate").permitAll()
.antMatchers("/helloAdmin").hasRole("Admin")
.antMatchers("/helloUser").hasRole("User")
.antMatchers("/students/").hasRole("Admin")
.antMatchers("/subjects/**").hasAnyRole("User","Admin")
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.and()
.logout()
.logoutSuccessUrl("/login?logout");
http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
http.addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class);

SSO/Oauth login on same application, Login based on UrL

I have spring MVC application and I am trying to register different SSO login on same application. For example if url is (admin.abc.com), It should login from microsoft SSO and if the url is abc.com it should redirect to google login.
Here is my code but when I run the code both sso open with giving me the option to choose.
Is there any way I can set sso login based on domain instead of select option.
#Autowired
ClientRegistrationRepository regRepository;
#Bean
public ClientRegistrationRepository clientRegistrationRepository() {
return new InMemoryClientRegistrationRepository(Arrays.asList(msClientRegistration(), googleSSOClientRegistration()));
}
and the configuration for antmatcher is like this
#Override
protected void configure(final HttpSecurity http)
throws Exception {
http.antMatcher("/**")
.authorizeRequests()
.antMatchers("/login.htm").authenticated()
.antMatchers("/**")
.permitAll().anyRequest()
.authenticated().and().logout()
.logoutSuccessHandler(oauthLogoutSuccessHandler())
.invalidateHttpSession(true)
.logoutUrl("/logout")
.and().oauth2Login()
.failureHandler(new CustomAuthenticationFailureHandler())
.authorizationEndpoint()
.authorizationRequestResolver(
new CustomAuthorizationRequestResolver(regRepository, "/oauth2/authorization"))
.and().tokenEndpoint()
.accessTokenResponseClient(authorizationCodeTokenResponseClient())
.and().and().headers()
.frameOptions()
.sameOrigin().and().csrf()
.disable();
}
How to add antMatcher configuration based on domain url? google sso for abc.com and admin.abc.com for microsoft login with OAuth2.
Instead of having this I want to redirect base on url's.. either Google login or Microsoft.

SecurityContextHolder.getContext().getAuthentication() returns null

I'm developing Spring boot and security web application with authorization and resource servers enabled. I have defined a set of users with roles assigned to them and have implemented roles based access to rest endpoints. Besides that my application has straightforward UI with web pages. Those pages display the same data that is on rest. I'm trying to implement the same roles based access to pages with ResourceServerConfig#configure and my current code:
public void configure(final HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/rest/products/add").hasAnyRole("ADMIN")
.anyRequest().authenticated()
.and().formLogin()
.loginPage("/login.jsf").permitAll()
.loginProcessingUrl("/login")
.defaultSuccessUrl("/login-successful", true)
.and().logout().permitAll();
}
This configuration works perfectly for REST controllers access with bearer token, but authorization with the login form leads to the redirect to the /login-successful and the message
Full authentication is required to access this resourceunauthorized is displayed.
The reason is that SecurityContextHolder.getContext().getAuthentication() for /login-successful request in spite it was correctly initialized in AbstractAuthenticationProcessingFilter#successfulAuthentication at the point of login form post. The same issue with other web pages in my app as well.
What should be added to the above configuration so that make it work for the REST and form login bought ?
Here is indicted that HttpSecurity configuration provided above is enough for authorization with form login to work correctly as far as .anyRequest().authenticated() should pass security context for all the resources in the application.
A similar case is described here but the reason over there is that an url was explicitly ignored in WebSecurity configurer.
The problem was in the fact that I was using deprecated #EnableResourceServer annotation that adds OAuth2AuthenticationProcessingFilter. For the form login authorization flow this is incorrect and that filter was removing authentication object from the SecurityContext. Here is indicated that OAuth2AuthenticationProcessingFilter shouldn't present in the filter chain for the form login authorization flow.
The reason why I was needed #EnableResourceServer annotation is that there are there is the bearer authentication flow in my application alongside with form login.
I replaced #EnableResourceServer annotation and ResourceServerConfigurerAdapter for the bearer authentication flow with Spring Security 5 resource server as http.oauth2ResourceServer() that is in WebSecurityConfigurerAdapter ( see here ). Finally the solution is with the following two WebSecurityConfigurerAdapter-s:
For bearer authorization flow:
#Configuration
#Order(2)
public class SecurityConfigRest extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
NimbusJwtDecoder jwtDecoder = Build custom JWT decoder;
http.csrf().disable()
.requestMatcher(new AntPathRequestMatcher("/rest/**"))
.authorizeRequests()
.mvcMatchers("/products/admin/**").hasRole("ADMIN")
.anyRequest().authenticated()
.and()
.oauth2ResourceServer().jwt().decoder(jwtDecoder);
}`
and for the form login authorization flow:
#Configuration
#Order(1)
#EnableWebSecurity
public class SecurityConfigFormLogin extends WebSecurityConfigurerAdapter {
protected void configure(HttpSecurity http) throws Exception {
http .requestMatcher(new AntPathRequestMatcher("/view/**"))
.authorizeRequests()
.anyRequest().authenticated()
.and()
.formLogin().loginPage("/view/login").permitAll()
.defaultSuccessUrl("/view/login-successful", true)
.and().logout()
.logoutUrl("/view/perform_logout")
.logoutSuccessUrl("/view/login");
}
These two WebSecurityConfigurerAdapter-s make it possible to separate those two authorization flows.
As far as Spring Security 5 resource server supports only JWT or Opaque tokens ( see here ) it requires additional configuration. Here is a detailed description of such a configuration for Spring Security 5 resource server.

Spring security : configure JWT with formLogin

I am trying to configure JWT filter with formLogin authentication .
(My server serve UI clients (thats why i need formLogin ) and i am exposing also Rest End Point (to be authenticated by JWT ) .
currently my JWT is working , but it seems that my Roles (anyRole) -- isnt working .
here is my configure method :
post login -> if I am trying to reach /kuku path - I get 302 and login page again .
if i am removing the addFilterBefore -> my roles is working fine .
protected void configure(HttpSecurity http) throws Exception {
http.
authorizeRequests()
.antMatchers("/login").permitAll()
.antMatchers("/").hasRole("ADMIN")
.antMatchers("/kuku/**").hasRole("ADMIN")
.anyRequest()
.authenticated()
.and()
.formLogin().defaultSuccessUrl("/inital.html", true)
;
http.addFilterBefore(new JwtFilter(), UsernamePasswordAuthenticationFilter.class);
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
String userName = "Admin"; // currently due to Vault IMPL - this input is hardcoded .
String password ="Admin"
auth.inMemoryAuthentication()
.withUser(userName).password(passwordEncoder().encode(password))
.roles("ADMIN");
}
Try adding csrf().disable() to your configure(http) method. This worked in my case where I have similar configuration as yours. Although, I suggest searching for whether or not this is secure, because this disables built-in csrf protection.

How Can I Customize Login Page for Oauth2 in Spring Webflux?

I just want to override default oauth2 login url (/login). How can I do that? The config I have tried without success:
#Bean
public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) {
http
.authorizeExchange().pathMatchers(permittedUrls).permitAll()
.anyExchange().authenticated()
.and()
.oauth2Login(Customizer.withDefaults()).formLogin().loginPage("/oauth2_login")
.authenticationSuccessHandler(this::onAuthenticationSuccess)
.and()
.csrf().disable();
return http.build();
I was hoping it will redirect to /oauth2_login url but it didn't work. It still redirect to /login. But this time it returns 404 instead of showing default login page.
The code above is customizing the login page for formLogin which is typically username/password based log in from a form. It's much easier to see what configuration you are impacting using the new lambda style approach, so I have updated the entire configuration to use it. If you want to customize the login page for oauth2Login, then you should change the login page on it. For example:
#Bean
public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) {
http
.authorizeExchange(exchanges -> exchanges
.pathMatchers(permittedUrls).permitAll()
.anyExchange().authenticated()
)
.oauth2Login(oauth2 -> oauth2
// you now must render a log in page for the URL /login
.loginPage("/login")
);
// remove formLogin that was for a username/password based log in
// if you are doing oauth2 login I'm guessing you allow users to work within a browser, so you should not disable csrf
return http.build();
}

Resources