disable spring formlogin and basic auth - spring-boot

I have the following spring boot 2.0 config but I am still getting the basic auth login screen. I DO NOT want to disable all spring security like almost every post on the internet suggests. I only want to stop the form login page and basic auth so I can use my own.
I have seen all the suggestions with permitAll and exclude = {SecurityAutoConfiguration.class} and a few others that I can't remember anymore. Those are not what I want. I want to use spring security but I wan my config not Spring Boots. Yes I know many people are going to say this is a duplicate but I disagree because all the other answers are to disable spring security completely and not just stop the stupid login page.
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(securedEnabled = true)
public class CustomSecurity extends WebSecurityConfigurerAdapter {
private final RememberMeServices rememberMeService;
private final AuthenticationProvider customAuthProvider;
#Value("${server.session.cookie.secure:true}")
private boolean useSecureCookie;
#Inject
public CustomSecurity(RememberMeServices rememberMeService, AuthenticationProvider customAuthProvider) {
super(true);
this.rememberMeService = rememberMeService;
this.bouncerAuthProvider = bouncerAuthProvider;
}
#Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/v2/**").antMatchers("/webjars/**").antMatchers("/swagger-resources/**")
.antMatchers("/swagger-ui.html");
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.httpBasic().disable().formLogin().disable();
http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).headers().frameOptions().disable();
http.authenticationProvider(customAuthProvider).authorizeRequests().antMatchers("/health").permitAll()
.anyRequest().authenticated();
http.rememberMe().rememberMeServices(rememberMeService).useSecureCookie(useSecureCookie);
http.exceptionHandling().authenticationEntryPoint(new ForbiddenEntryPoint());
}
}

If you want to redirect to your own login page, i can show your sample code and configuration
remove the http.httpBasic().disable().formLogin().disable();, you should set your own login page to redirect instead of disable form login
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().antMatchers("/my_login").permitAll().and().authorizeRequests().anyRequest().authenticated();
http.formLogin().loginPage("/my_login");
}
then create your own LoginController
#Controller
public class LoginController {
#RequestMapping("/my_login")
public ModelAndView myLogin() {
return new ModelAndView("login");
}
}
you can specified the login with thymeleaf view resolver

Related

Spring security dynamic Role permission role and permission not working

I am implementing a spring security with roles and permission which i fetch from database. It works fine in the case of mapped url only. For unmapped url i an not getting 403. Below is my http configuration. Any help appreciated.
#Configuration
#EnableWebSecurity
#RequiredArgsConstructor
public class SecurityConfigure extends WebSecurityConfigurerAdapter {
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(customUserDetailsService);
}
#Override
public void configure(HttpSecurity httpSecurity) throws Exception {
List<Role> roleModules = roleActionRepository.findAll();
ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry urlRegistry = httpSecurity.authorizeRequests();
httpSecurity.csrf().disable();
urlRegistry.antMatchers(
"/authenticate",
"/public/**",
"/common/**"
).permitAll();
roleModules.forEach(roleAction -> {
urlRegistry.antMatchers(HttpMethod.valueOf(module.getType()), module.getName()).hasAuthority(roleAction.getName());
});
urlRegistry.anyRequest().authenticated()
.and().csrf().disable().sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS);
httpSecurity.addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class);
}
#Bean
#Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
}
Lets say i have one url mapping /employee/** which i get from database. For that my code works fine.
But lets say i have another url like /user/** which is not configured for any role. So ideally on one can access that end point. But i am able to access that point without role assign. So how i can prevent this thing.
You can also find out the screen shot of the role mapping
when ever the urlRegistry.anyRequest().authenticated() called the 4th indenxing is added.

isAuthenticated annotation does not prevent access

I have a following controller:
#RestController
#RequestMapping("/payments")
public class PaymentController {
#Autowired
PaymentService paymentService;
#Autowired
private Environment env;
#PostMapping("/create")
#PreAuthorize("isAuthenticated()")
public ResponseEntity<String> create(#Valid #RequestBody DownPayment downpayment) {
Customer customer;
Charge charge;
User user = new User();
............
}
}
WebSecurity config:
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class SpringSecurityWebAppConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable();
}
}
I want to use preAuthorize annotation (method level) instead of http security. The payments/create endpoint is publicly accessible which works without throwing any unauthorised error.
Set a breakpoint and check what is contained in the SecurityContextHolder, e.g. like that: SecurityContextHolder.getContext().getAuthentication(). I suggest you add what is contained in the SecurityContextHolder to your question so that people can help you better.
My assumption is that you have anonymous access enabled, which means that an anonymous authentication object is placed in the SecurityContextHolder if no other authentication was set (e.g. by a AuthenticationTokenFilter). Spring detects this as an authentication, so that the access to your API is not prevented by the #PreAuthorize("isAuthenticated()") annotation. Generally you should consider if it might not be better to use role-based access rules, as these are more fine-granular.
You can disable anonymous access as follows:
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.anonymous().disable()
.csrf().disable();
}

Can not retrieve Principal from Spring Okta (CRA SPA)

I am currently trying to test out Okta with SPA front end (Create-React-App) and a Spring Boot application.
Currently I have the apps working, in that a user logins on the front end (via okta). The user can then access protected resources from server (spring boot). Hence the integration works well and nice.
My issue is I can't access the Principal on my Rest Controller.
ENV
Note: Spring-Security-Starter is NOT on the classpath just the OAuth2 autoconf
Spring Boot 2.0.6.RELEASE
okta-spring-boot-starter:0.6.1
spring-security-oauth2-autoconfigure:2.0.6.RELEASE'
Spring Configuration
okta.oauth2.issuer=https://dev-886281.oktapreview.com/oauth2/default
okta.oauth2.clientId={ clientId }
okta.oauth2.audience=api://default
okta.oauth2.scopeClaim=scp
okta.oauth2.rolesClaim=groups
security.oauth2.resource.user-info-uri=https://dev-886281.oktapreview.com/oauth2/default/v1/userinfo
Okta Service Configuration
Application type: Single Page App (SPA)
Allowed grant types: Implicit
Allow Access Token with implicit grant type: true
Controller
#RestController
#RequestMapping("/products")
public class ProductController {
...
#GetMapping
public ResponseEntity<List<ProductEntity>> getAllProducts(Principal principal) {
SpringBoot
#EnableResourceServer
#SpringBootApplication
public class CartyApplication {
public static void main(String[] args) {
SpringApplication.run(CartyApplication.class, args);
}
#EnableGlobalMethodSecurity(prePostEnabled = true)
protected static class GlobalSecurityConfiguration extends GlobalMethodSecurityConfiguration {
#Override
protected MethodSecurityExpressionHandler createExpressionHandler() {
return new OAuth2MethodSecurityExpressionHandler();
}
}
#Bean
protected ResourceServerConfigurerAdapter resourceServerConfigurerAdapter() {
return new ResourceServerConfigurerAdapter() {
#Override
public void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers(HttpMethod.OPTIONS,"/**").permitAll()
.anyRequest().authenticated();
}
};
}
Once again the overall integration is working fine, users can only access protected resources once they've signed in via okta, I'm just wondering how to get the users details from okta on the controller.
Thanks in advance.
P.S soz for the code dump
EDIT: Removed snippets and added full CartyApplication class
EDIT2: Added repo - https://github.com/Verric/carty-temp
I have a feeling you might be missing this:
#EnableGlobalMethodSecurity(prePostEnabled = true)
protected static class GlobalSecurityConfiguration extends GlobalMethodSecurityConfiguration {
#Override
protected MethodSecurityExpressionHandler createExpressionHandler() {
return new OAuth2MethodSecurityExpressionHandler();
}
}
I'm guessing should remove the .antMatchers("/**").permitAll() line.
See: https://docs.spring.io/spring-security/site/docs/current/reference/html/jc.html#CO3-2
I'm guessing you want to protect all/most of your endpoints? I'd recommend only allowing specific routes, and protecting everything else.

Unable to set up basic authentication with Spring Boot REST API

I'm trying to set up a RESTful API with Spring Boot and I'm trying to enable basic authentication. How come I keep hitting a 403 Access Denied error? I'm sending my credentials as a header in Postman (see image attached). If I remove .anyRequest.authenticated(), it works fine. I don't want to remove that though because I would like basic authentication for every endpoint. What am I doing wrong?
Application.java
#SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
SecurityConfiguration.java
#Configuration
#EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/h2-console/*").permitAll()
.anyRequest().authenticated();
http.csrf().disable();
http.headers().frameOptions().disable();
}
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
.withUser("user").password("password").roles("USER");
}
}
Controller.java
#RestController
public class Controller {
#RequestMapping("/test")
public String index() {
return "Greetings from Spring Boot!";
}
}
After digging around in the Spring docs, it seems I understand what each of the chained method calls are for.
Anyway, the simple answer is that I needed .and().httpBasic() to enable Basic HTTP Authentication over my REST API.
.anyRequest().authenticated() simply mandates that every request is authenticated, but did not specify what method. Adding basic authentication means we can use basic auth to authenticate a user.
See more.

Multiple WebSecurityConfigurerAdapter: one as a library, in the other users can add their own security access

I am creating a Spring Security configuration to be used as a library by any developer who wants to create a Stormpath Spring application secured by Spring Security.
For that I have sub-classed WebSecurityConfigurerAdapter and defined the Stormpath Access Controls in configure(HttpSecurity) as well as the Stormpath AuthenticationProvider by means of configure(AuthenticationManagerBuilder). All this can be seen in this abstract class and its concrete sub-class:
#Order(99)
public abstract class AbstractStormpathWebSecurityConfiguration extends WebSecurityConfigurerAdapter {
//Removed properties and beans for the sake of keeping focus on the important stuff
/**
* The pre-defined Stormpath access control settings are defined here.
*
* #param http the {#link HttpSecurity} to be modified
* #throws Exception if an error occurs
*/
protected void configure(HttpSecurity http, AuthenticationSuccessHandler successHandler, LogoutHandler logoutHandler)
throws Exception {
if (loginEnabled) {
http
.formLogin()
.loginPage(loginUri)
.defaultSuccessUrl(loginNextUri)
.successHandler(successHandler)
.usernameParameter("login")
.passwordParameter("password");
}
if (logoutEnabled) {
http
.logout()
.invalidateHttpSession(true)
.logoutUrl(logoutUri)
.logoutSuccessUrl(logoutNextUri)
.addLogoutHandler(logoutHandler);
}
if (!csrfProtectionEnabled) {
http.csrf().disable();
} else {
//Let's configure HttpSessionCsrfTokenRepository to play nicely with our Controllers' forms
http.csrf().csrfTokenRepository(stormpathCsrfTokenRepository());
}
}
/**
* Method to specify the {#link AuthenticationProvider} that Spring Security will use when processing authentications.
*
* #param auth the {#link AuthenticationManagerBuilder} to use
* #param authenticationProvider the {#link AuthenticationProvider} to whom Spring Security will delegate authentication attempts
* #throws Exception if an error occurs
*/
protected void configure(AuthenticationManagerBuilder auth, AuthenticationProvider authenticationProvider) throws Exception {
auth.authenticationProvider(authenticationProvider);
}
}
#Configuration
public class StormpathWebSecurityConfiguration extends AbstractStormpathWebSecurityConfiguration {
//Removed beans for the sake of keeping focus on the important stuff
#Override
protected final void configure(HttpSecurity http) throws Exception {
configure(http, stormpathAuthenticationSuccessHandler(), stormpathLogoutHandler());
}
#Override
protected final void configure(AuthenticationManagerBuilder auth) throws Exception {
configure(auth, super.stormpathAuthenticationProvider);
}
}
In short, we are basically defining our login and logout mechanisms and integrating our CSRF code to play nicely with Spring Security's one.
Up to this point everything works OK.
But this is just the "library" and we want users to build their own applications on top of it.
So, we have created a Sample application to demonstrate how a user will use our library.
Basically users will want to create their own WebSecurityConfigurerAdapter. Like this:
#EnableStormpathWebSecurity
#Configuration
#ComponentScan
#PropertySource("classpath:application.properties")
#Order(1)
public class SpringSecurityWebAppConfig extends WebSecurityConfigurerAdapter {
/**
* {#inheritDoc}
*/
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().antMatchers("/restricted").fullyAuthenticated();
}
}
In case this is actually needed, the WebApplicationInitializer looks like this:
public class WebAppInitializer implements WebApplicationInitializer {
#Override
public void onStartup(ServletContext sc) throws ServletException {
AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
context.register(SpringSecurityWebAppConfig.class);
context.register(StormpathMethodSecurityConfiguration.class);
sc.addListener(new ContextLoaderListener(context));
ServletRegistration.Dynamic dispatcher = sc.addServlet("dispatcher", new DispatcherServlet(context));
dispatcher.setLoadOnStartup(1);
dispatcher.addMapping("/");
//Stormpath Filter
FilterRegistration.Dynamic filter = sc.addFilter("stormpathFilter", new DelegatingFilterProxy());
EnumSet<DispatcherType> types =
EnumSet.of(DispatcherType.ERROR, DispatcherType.FORWARD, DispatcherType.INCLUDE, DispatcherType.REQUEST);
filter.addMappingForUrlPatterns(types, false, "/*");
//Spring Security Filter
FilterRegistration.Dynamic securityFilter = sc.addFilter(AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME, DelegatingFilterProxy.class);
securityFilter.addMappingForUrlPatterns(EnumSet.allOf(DispatcherType.class), false, "/*");
}
}
All this code boots up correctly. If I go to localhost:8080 I see the welcome screen. If I go to localhost:8080/login I see the login screen. But, if I go to localhost:8080/restricted I should be redirected to the login page since we have this line: http.authorizeRequests().antMatchers("/restricted").fullyAuthenticated();. However I am seeing the Access Denied page instead.
Then, if I add the login url in the App's access control, like this:
protected void configure(HttpSecurity http) throws Exception {
http
.formLogin().loginPage("/login")
.and()
.authorizeRequests().antMatchers("/restricted").fullyAuthenticated();
}
It now redirects me to the login page but as soon as I submit the credentials I get an CSRF problem meaning that all our configuration is not actually part of this filter chain.
When I debug it all it seems that each WebApplicationInitializer is having its own instance with its own Filter Chain. I would expect them to be concatenated somehow but it seems that it is not actually happening...
Anyone has ever tried something like this?
BTW: As a workaround users can do public class SpringSecurityWebAppConfig extends StormpathWebSecurityConfiguration instead of SpringSecurityWebAppConfig extends WebSecurityConfigurerAdapter. This way it works but I want users to have pure Spring Security code and extending from our StormpathWebSecurityConfiguration diverges from that goal.
All the code can be seen here. The Stormpath Spring Security library for Spring is under extensions/spring/stormpath-spring-security-webmvc. The Sample App using the library is under examples/spring-security-webmvc.
It is very simple to run... You just need to register to Stormpath as explained here. Then you can checkout the spring_security_extension_redirect_to_login_not_working branch and start the sample app like this:
$ git clone git#github.com:mrioan/stormpath-sdk-java.git
$ git checkout spring_security_extension_redirect_to_login_not_working
$ mvn install -DskipTests=true
$ cd examples/spring-security-webmvc
$ mvn jetty:run
Then you can go to localhost:8080/restricted to see that you are not being redirected to the login page.
Any help is very much appreciated!
In my experience there are issues with having multiple WebSecurityConfigurers messing with the security configuration on startup.
The best way to solve this is to make your library configuration into SecurityConfigurerAdapters that can be applied where appropriate.
public class StormpathHttpSecurityConfigurer
extends AbstractStormpathWebSecurityConfiguration
implements SecurityConfigurer<DefaultSecurityFilterChain, HttpSecurity> {
//Removed beans for the sake of keeping focus on the important stuff
#Override
protected final void configure(HttpSecurity http) throws Exception {
configure(http, stormpathAuthenticationSuccessHandler(), stormpathLogoutHandler());
}
}
public class StormpathAuthenticationManagerConfigurer
extends AbstractStormpathWebSecurityConfiguration
implements SecurityConfigurer<AuthenticationManager, AuthenticationManagerBuilder> {
//Removed beans for the sake of keeping focus on the important stuff
#Override
protected final void configure(AuthenticationManagerBuilder auth) throws Exception {
configure(auth, super.stormpathAuthenticationProvider);
}
}
You then have your users apply these in their own configuration:
#EnableStormpathWebSecurity
#Configuration
#ComponentScan
#PropertySource("classpath:application.properties")
#Order(1)
public class SpringSecurityWebAppConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/restricted").fullyAuthenticated()
.and()
.apply(new StormPathHttpSecurityConfigurer(...))
;
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.apply(new StormPathAuthenticationManagerConfigurer(...));
}
}
It's definitely the problem regarding either order of your Antmatchers or hasn't specified ROLES of users that you permit to access the URL.
What do you have anything above "/restricted"?
Is something completely blocking anything below that URL? You should specify more specific URLS first then, generalised URLs.
Try configuring above URL properly (or tell me what it is so I can help you out), perhaps apply "fullyAuthenticated" also "permitAll" ROLEs on the parent URL of "/restricted".

Resources