Manage User Redirect Spring Security - spring-boot

i'm new to spring security can any one guide me how to do this. my configuration class of spring security is mention below: i made my home page "/" visible to all user. so i didn't use "/" in http.antmatchs("/") in home page my nav bar has link for "login and signup". after successful login user redirect to "buyer/list" endpoint which i mention in configuration. what i want is "login user" can't visit homepage again. for this i also use
Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
for "/" mapping controller, but it throw nullPointerException. can any one guide me how do i proceed. if there is other approach please mention.
Configuration
#EnableWebSecurity
public class SecureConfig extends WebSecurityConfigurerAdapter {
#Autowired
UserDetailsService userDetailsService;
#Value("${winni.auth.exit}")
private String authExit;
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService)
.passwordEncoder(passwordEncoder());
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.requestMatchers()
.antMatchers("/login", "/web/**", "/action/**", "/cart/**", "/cart/xhr/**", "/buyer/**","/profile/**","/chat/**","/order/**")
.and()
.authorizeRequests()
.anyRequest().authenticated()
.and()
.formLogin().loginPage("/login").defaultSuccessUrl("/buyer/list", true).permitAll().and()
.logout().logoutSuccessUrl(authExit);
}
#Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
#Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/assets/**");
}
}

So you want that only unauthenticated users can access "/" and "/login" and only authenticated users on the other pages. I would do something like this:
http
.authorizeRequests()
.antMatchers("/web/**", "/action/**", "/cart/**", "/cart/xhr/**", "/buyer/**","/profile/**","/chat/**","/order/**")
.authenticated()
.and()
.antMatchers("/", "/login")
.anonymous()
.and()
.formLogin().loginPage("/login")
.defaultSuccessUrl("/buyer/list", true)
.and()
.logout()
.logoutSuccessUrl("/");

Related

Spring security - How to use role based authentication for different domains?

There is a project with Spring boot back-end on running on localhost:8080 and 2 front-end angular applications on localhost:4200 (User website) and localhost:4201(Admin website).How can i configure spring security so that it allows only users with role - ROLE_USER,ROLE_ADMIN in User website and users with role -ROLE_ADMIN should have access to Admin Website.
Currently both users are able to access both wesbite.Is there any way to restrict certain domains rather restricting paths(URLs) to users.
Current config -
#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter{
#Autowired
Environment env;
#Autowired
UserSecurityService useSecurityService;
private BCryptPasswordEncoder passwordEncoder() {
return SecurityUtility.passwordEncoder();
}
private static final String[] PUBLIC_MATHCES= {
"/css/**",
"/js/**",
"/images/**",
"/book/**",
"/user/**",
"/media/**"
};
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(useSecurityService).passwordEncoder(passwordEncoder());
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers(PUBLIC_MATHCES).permitAll()
.anyRequest().authenticated()
.and();
http.csrf().disable()
.cors()
.and()
.httpBasic();
}
#Bean
public HttpSessionIdResolver httpSessionStrategy() {
return HeaderHttpSessionIdResolver.xAuthToken();
}
}
suppose all of your configurations configured properly, then you can make use of the role restriction mechanism as the below sample :
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests(authorize - > {
authorize
.antMatchers("/h2-console/**").permitAll() //do not use in production!
.antMatchers("/css/**", "/js/**", "/images/**", "/book/**", "/user/**", "/media/**").permitAll()
.antMatchers("/website/find", "/main*").permitAll()
.antMatchers(HttpMethod.GET, "/userweb/v1/data/**").permitAll()
.mvcMatchers(HttpMethod.DELETE, "/userweb/v1/info/**").hasRole("ADMIN")
.mvcMatchers(HttpMethod.GET, "/userweb/v1/item/{upc}").permitAll()
.mvcMatchers("/admin/main").hasAnyRole("USER", "ADMIN")
.mvcMatchers(HttpMethod.GET, "/user/api/v1/normal")
.hasAnyRole("USER", "ADMIN", "FOO");
})
.authorizeRequests()
.anyRequest().authenticated()
.and()
.cors()
.and()
.httpBasic()
.and().csrf().disable();
}

spring security 2 login form call one another without authenticating

I am writing a spring security code with 2 login forms and 2 login URLs. The problem is that when I pres on sign in button on any login form without even true authenticating it directs me to the other login form. When I try the other login form the same happens. If someone has any clue is welcome to comment.
My code is:
#Order(1)
#Configuration
#EnableWebSecurity
//#Order(Ordered.LOWEST_PRECEDENCE)
public class SecurityConfigurationAdmin extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.antMatcher("/adminlogin*")
.authorizeRequests()
.antMatchers(
"/login2",
"/login",
"/registration**",
"/js/**",
"/css/**",
"/img/**").permitAll()
.antMatchers("/adminlogin*").hasRole("USER2")
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login2").permitAll()
// .loginProcessingUrl("/login22")
.usernameParameter("username2")
.passwordParameter("password2")
.successForwardUrl("/adminlogin")
.defaultSuccessUrl("/adminlogin",true)
// .failureUrl("/login2")
.permitAll()
.and()
.logout()
.invalidateHttpSession(true)
.clearAuthentication(true)
.logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
.logoutSuccessUrl("/?logout")
.permitAll();
}
#Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("admin").password("{noop}admin").roles("USER2");
}
and :
#Order(2)
#Configuration
#EnableWebSecurity
//#Order(Ordered.HIGHEST_PRECEDENCE)
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
#Autowired
private UserService userService;
#Bean
public BCryptPasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.antMatcher("/librarianlogin*")
.authorizeRequests()
.antMatchers(
"/login",
"/login2",
"/registration**",
"/js/**",
"/css/**",
"/img/**").permitAll()
.antMatchers("/librarianlogin").hasRole("USER")
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login").permitAll()
// .loginProcessingUrl("/login1")
.successForwardUrl("/librarianlogin")
.defaultSuccessUrl("/librarianlogin",true)
// .failureUrl("/login")
.permitAll()
.and()
.logout()
.invalidateHttpSession(true)
.clearAuthentication(true)
.logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
.logoutSuccessUrl("/?logout")
.permitAll();
}
#Bean
public DaoAuthenticationProvider authenticationProvider() {
DaoAuthenticationProvider auth = new DaoAuthenticationProvider();
auth.setUserDetailsService(userService);
auth.setPasswordEncoder(passwordEncoder());
return auth;
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(authenticationProvider());
}
}
I m sure that everything that is missing is in the WebSecurityConfigurerAdapter classes since when I compile the code separately from the 2 log in forms they work perfectly. When i combine them together something goes wrong.
Looking at your configuration, it appears that you want to have two separate user bases, one for administrators, and one for librarians. You are using different login pages in order to know which is which.
To do this, you need to have multiple filter chains, which is how you've already begun. I'd suggest some tweaks, though.
First, the top-level antMatcher call is for segmenting out your application. For example, it's common for all admin pages to be served under the /admin path. In that case, you can do:
#Order(1)
#Configuration
public class AdminSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.antMatcher("/admin/**")
.authorizeRequests((authz) -> authz
.mvcMatchers("/error").permitAll()
.anyRequest().authenticated()
)
.formLogin((form) -> form
.loginPage("/admin/login").permitAll()
);
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
UserDetailsService adminUsers = // ... construct
auth.userDetailsService(adminUsers);
}
}
for the admin's part of the site, and:
#Order(2)
#Configuration
public LibrarianSecurityConfig extends WebSecurityConfigurerAdatper {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.antMatcher("/**")
.authorizeRequests((authz) -> authz
.anyRequest().authenticated()
)
.formLogin((form) -> form
.loginPage("/login").permitAll()
);
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
UserDetailsService users = // ...
auth.userDetailsService(adminUsers);
}
}
for the librarian part.
Some things to keep in mind:
Order matters. When you have multiple filter chains, Spring Security will pick the first chain whose matcher matches the request path. So, /admin/** goes first since it is a smaller expression than /**
You need to configure your front end to support CSRF since Spring Security expects CSRF tokens by default for any POST request
Permitting /error is important at least while debugging your login setup since otherwise any errors will get swallowed behind the authentication wall
You can find the complete code in this sample.

Spring security Basic Auth and Form login for the same API

I would like to access all my API's via two authentication mechanisms, Basic Auth & Form login. I know that there are existing questions, but, the answers did not work for me, and my use case is a little bit different.
My config:
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig {
#Configuration
#Order(1)
public static class SecurityConfigBasicAuth extends WebSecurityConfigurerAdapter {
final private RestAuthenticationEntryPoint restAuthenticationEntryPoint;
#Autowired
public SecurityConfigBasicAuth(RestAuthenticationEntryPoint restAuthenticationEntryPoint,
#Qualifier("customUserDetailsService") UserDetailsService userDetailsService) {
this.restAuthenticationEntryPoint = restAuthenticationEntryPoint;
this.userDetailsService = userDetailsService;
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService);
auth.authenticationProvider(authenticationProvider());
}
// #Bean authenticationProvider()
// #Bean passwordEncoder()
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().anyRequest().authenticated()
.and()
.cors()
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.csrf().disable()
.httpBasic()
.authenticationEntryPoint(restAuthenticationEntryPoint)
.and()
.formLogin().disable()
.logout().disable();
}
}
#Configuration
public static class SecurityConfigFormLogin extends WebSecurityConfigurerAdapter {
final private RestAuthenticationEntryPoint restAuthenticationEntryPoint;
final private RestfulSavedRequestAwareAuthenticationSuccessHandler restfulSavedRequestAwareAuthenticationSuccessHandler;
final private CustomAuthenticationProvider customAuthenticationProvider;
#Autowired
public SecurityConfigFormLogin(RestAuthenticationEntryPoint restAuthenticationEntryPoint,
RestfulSavedRequestAwareAuthenticationSuccessHandler restfulSavedRequestAwareAuthenticationSuccessHandler,
CustomAuthenticationProvider hashAuthenticationProvider) {
this.restAuthenticationEntryPoint = restAuthenticationEntryPoint;
this.restfulSavedRequestAwareAuthenticationSuccessHandler = restfulSavedRequestAwareAuthenticationSuccessHandler;
this.customAuthenticationProvider = customAuthenticationProvider;
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(customAuthenticationProvider);
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().anyRequest().authenticated()
.and()
.cors()
.and()
.csrf().disable()
.exceptionHandling()
.authenticationEntryPoint(restAuthenticationEntryPoint)
.and()
.csrf().disable()
.httpBasic().disable()
.formLogin()
.usernameParameter("id1")
.passwordParameter("Id2")
.loginProcessingUrl("/test/login")
.successHandler(restfulSavedRequestAwareAuthenticationSuccessHandler)
.failureHandler(myFailureHandler())
.and()
.logout();
}
// #Bean myFailureHandler()
}
}
As you can see, I defined two 'WebSecurityConfigurerAdapters', one for Basic Auth, and one for Form login. The Form login is REST compatible (does not redirect, but gives HTTP responses).
The problem is as follows: The first 'WebSecurityConfigurerAdapter' that is loaded works and overrides the second. The above example, makes it possible to use basic auth, but I cannot login on POST '/test/login', I get a:
{
"timestamp": 1534164906450,
"status": 401,
"error": "Unauthorized",
"message": "Unauthorized",
"path": "/test/login"
}
Update fixed: the key was to use the 'requestMatchers()', see answer section for solution (as suggested by jzheaux)
Okay, this is how I fixed this:
I configured the Basic Auth configuration as:
protected void configure(HttpSecurity http) throws Exception {
http.requestMatchers()
.antMatchers("/api/**")
.and()
.cors()
.and()
.csrf().disable()
.httpBasic()
.authenticationEntryPoint(restAuthenticationEntryPoint)
.and();
}
If you do not want that the basic authentication returning new cookie with new JSESSIONID, add:
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.NEVER)
.sessionFixation()
.migrateSession()
The Form login configuration as:
protected void configure(HttpSecurity http) throws Exception {
http.requestMatchers()
.antMatchers(HttpMethod.POST, "/test/login")
.and()
.cors()
.and()
.csrf().disable()
.exceptionHandling()
.authenticationEntryPoint(restAuthenticationEntryPoint)
.and()
.formLogin()
.usernameParameter("id1")
.passwordParameter("id2")
.loginProcessingUrl("/test/login")
.successHandler(authenticationSuccessHandler)
.failureHandler(myFailureHandler())
.and()
.logout();
}
Now, it is possible for me to authenticate via the Form login configuration, and use the cookie session id to call /api/** (configured in the Basic Auth configuration). I can also just use the Basic Auth authentication ofcourse.

JHipster OAuth2 server - login page for /oauth/authorize

tl;dr;
I want to make custom working login page when user is redirected to /oauth/authorize, in jhipster template app I manage to display my login page but it is just redirecting to itself no matter what credentials are used or if I remove
.requestMatchers().antMatchers("/oauth/authorize")
from WebSecurityConfigurerAdapter page works fine but /oauth/token returns:
error: "unauthorized"
error_description: "There is no client authentication. Try adding an appropriate authentication filter."
Long description:
I'm using jhipster template app for resource server with some small admin front end. Except of this I want other client apps to be able to use my resource server, but user login should stay on my app.
Example Journey:
Client app is redirecting user to my app:
127.0.0.1:8080/oauth/authorize?
response_type=code&client_id=kbExplorer&redirect_uri=http://localhost
Login page is served for a user
User choose scopes he wants to give
Server is redirecting to redirect_uri with authorization code
App uses code to get refresh token
127.0.0.1:8080/oauth/token?grand_type=authorization_code&code={code}
This is typical journey.
Problem starts when I want to change basic http login window, to my own login page.
First thing I've done was changing:
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
#Order(Ordered.HIGHEST_PRECEDENCE)
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
#Inject
private UserDetailsService userDetailsService;
#Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
#Inject
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth
.userDetailsService(userDetailsService)
.passwordEncoder(passwordEncoder());
}
#Override
public void configure(WebSecurity web) throws Exception {
web.ignoring()
.antMatchers("/scripts/**/*.{js,html}")
.antMatchers("/bower_components/**")
.antMatchers("/i18n/**")
.antMatchers("/assets/**")
.antMatchers("/swagger-ui/index.html")
.antMatchers("/api/register")
.antMatchers("/api/activate")
.antMatchers("/api/account/reset_password/init")
.antMatchers("/api/account/reset_password/finish")
.antMatchers("/test/**")
.antMatchers("/console/**");
}
#Override
public void configure(HttpSecurity http) throws Exception {
http
//.httpBasic().realmName("LES")
//.and()
.requestMatchers().antMatchers("/oauth/authorize")
.and()
.authorizeRequests()
.antMatchers("/api/logput").permitAll()
.antMatchers("/oauth/authorize").authenticated()
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED)
.and()
.formLogin().loginPage("/login").permitAll().and().csrf().disable();
}
#Override
#Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
#Bean
public SecurityEvaluationContextExtension securityEvaluationContextExtension() {
return new SecurityEvaluationContextExtension();
}
}
Thanks to that I'm getting custom login page served from mvc controller:
#Configuration
public class MvcConfig extends WebMvcConfigurerAdapter {
#Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/login").setViewName("login");
}
}
But there is a problem right now, when I go to /oauth/authorize login page is served and it is ok, except of whatever you will put there it will always redirect you back to this login page.
I've noticed that if I only remove:
#Override
public void configure(HttpSecurity http) throws Exception {
http
//.httpBasic().realmName("LES")
//.and()
// This is the line I'm removing:
//.requestMatchers().antMatchers("/oauth/authorize")
//.and()
.authorizeRequests()
.antMatchers("/api/logput").permitAll()
.antMatchers("/oauth/authorize").authenticated()
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED)
.and()
.formLogin().loginPage("/login").permitAll().and().csrf().disable();
}
Whole login works fine. But now admin app stops (this is pure jhipster angularjs template). Just opening this app produces an error:
error: "Internal Server Error"
exception: "java.lang.IllegalStateException"
message: "Request processing failed; nested exception is java.lang.IllegalStateException: User not found!"
path: "/api/account"
status: 500
timestamp: "2016-01-22T11:33:08.286+0000"
Attempt to log in by default grand_type=password produce:
error: "unauthorized"
error_description: "There is no client authentication. Try adding an appropriate authentication filter."
This is my OAuth2ServerConfiguration (Basically its pure jhipser template):
#Configuration
public class OAuth2ServerConfiguration {
#Configuration
#EnableResourceServer
protected static class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {
#Inject
private Http401UnauthorizedEntryPoint authenticationEntryPoint;
#Inject
private AjaxLogoutSuccessHandler ajaxLogoutSuccessHandler;
#Override
public void configure(HttpSecurity http) throws Exception {
http
.exceptionHandling()
.authenticationEntryPoint(authenticationEntryPoint)
.and()
.logout()
.logoutUrl("/api/logout")
.logoutSuccessHandler(ajaxLogoutSuccessHandler)
.and()
.csrf()
.requireCsrfProtectionMatcher(new AntPathRequestMatcher("/oauth/authorize")) // csfr (my own change)
.disable()
.headers()
.frameOptions().disable()
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
.antMatchers(HttpMethod.OPTIONS, "/**").permitAll()
.antMatchers("/api/authenticate").permitAll()
.antMatchers("/api/register").permitAll()
.antMatchers("/api/logs/**").hasAnyAuthority(AuthoritiesConstants.ADMIN)
.antMatchers("/api/**").authenticated()
.antMatchers("/metrics/**").hasAuthority(AuthoritiesConstants.ADMIN)
.antMatchers("/health/**").hasAuthority(AuthoritiesConstants.ADMIN)
.antMatchers("/trace/**").hasAuthority(AuthoritiesConstants.ADMIN)
.antMatchers("/dump/**").hasAuthority(AuthoritiesConstants.ADMIN)
.antMatchers("/shutdown/**").hasAuthority(AuthoritiesConstants.ADMIN)
.antMatchers("/beans/**").hasAuthority(AuthoritiesConstants.ADMIN)
.antMatchers("/configprops/**").hasAuthority(AuthoritiesConstants.ADMIN)
.antMatchers("/info/**").hasAuthority(AuthoritiesConstants.ADMIN)
.antMatchers("/autoconfig/**").hasAuthority(AuthoritiesConstants.ADMIN)
.antMatchers("/env/**").hasAuthority(AuthoritiesConstants.ADMIN)
.antMatchers("/trace/**").hasAuthority(AuthoritiesConstants.ADMIN)
.antMatchers("/liquibase/**").hasAuthority(AuthoritiesConstants.ADMIN)
.antMatchers("/api-docs/**").hasAuthority(AuthoritiesConstants.ADMIN)
.antMatchers("/protected/**").authenticated();
}
}
#Configuration
#EnableAuthorizationServer
protected static class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter {
#Inject
Environment env;
#Inject
private DataSource dataSource;
#Inject
private JHipsterProperties jHipsterProperties;
#Bean
public TokenStore tokenStore() {
return new JdbcTokenStore(dataSource);
}
#Inject
#Qualifier("authenticationManagerBean")
private AuthenticationManager authenticationManager;
#Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints)
throws Exception {
endpoints
.tokenStore(tokenStore())
.authenticationManager(authenticationManager);
}
#Override
public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
oauthServer.allowFormAuthenticationForClients();
}
#Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
if(env.acceptsProfiles(Constants.SPRING_PROFILE_PRODUCTION)) {
clients.jdbc(dataSource);
}else{
clients
.jdbc(dataSource)
.withClient(jHipsterProperties.getSecurity().getAuthentication().getOauth().getClientid())
.scopes("read", "write")
.authorities(AuthoritiesConstants.ADMIN, AuthoritiesConstants.USER)
.authorizedGrantTypes("password", "refresh_token", "authorization_code", "implicit")
.secret(jHipsterProperties.getSecurity().getAuthentication().getOauth().getSecret())
.accessTokenValiditySeconds(jHipsterProperties.getSecurity().getAuthentication().getOauth().getTokenValidityInSeconds())
.and()
.withClient("kbExplorer")
.scopes("read", "write")
.authorities(AuthoritiesConstants.ADMIN, AuthoritiesConstants.USER)
.authorizedGrantTypes("password", "refresh_token", "authorization_code", "implicit")
.secret("kbExplorerAppSecret")
.accessTokenValiditySeconds(5)
.refreshTokenValiditySeconds(1800);
}
}
}
}
Question is:
How to make login page works, without breaking api in same time?
I had wrong matchers, login page was not working in my first option because I had no matcher for "/login" in configure method.
SecurityConfiguration class should be like this:
#Override
public void configure(HttpSecurity http) throws Exception {
http
.requestMatchers().antMatchers(HttpMethod.OPTIONS, "/**")
.antMatchers("/oauth/authorize","/login", "/oauth/confirm_access")
.and()
.authorizeRequests()
.antMatchers("/oauth/authorize").authenticated()
.and()
.formLogin().loginPage("/login").permitAll()
.and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED)
.and()
.csrf().disable();
}

Spring boot: Securing api endpoint with oauth2 while having mvc UI pages

I'm trying to get a spring-boot mvc application working with standard login while exposing some API endpoints with oAuth2 security.
Basically my requirements are as follows:
If a user hits the home page ("/") check if it's authenticated.
If not show the login form, else show the home page.
But a user should also be able to ask for an oauth authentication token and with that token acces /api/assignment/{id}.
I can get the standard login to work, and I can get the oauth2 to work but I can not get them to work together.
This is my configuration at the moment:
WebSecurityConfig
#Configuration
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private DataSource dataSource;
#Override
#Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
#Override
protected void configure(HttpSecurity http) throws Exception {
super.configure(http);
}
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.jdbcAuthentication().dataSource(this.dataSource).passwordEncoder(new BCryptPasswordEncoder());
}
}
OAuth2Config
#Configuration
#EnableResourceServer
#EnableAuthorizationServer
public class OAuth2Config {
protected static final String RESOURCE_ID = "oauthdemo";
#Configuration
#EnableResourceServer
protected static class ResourceServer extends ResourceServerConfigurerAdapter {
#Override
public void configure(HttpSecurity http) throws Exception {
http
.httpBasic().disable()
.authorizeRequests()
.antMatchers("/js/**", "/css/**", "/images/**", "/webjars/**", "/login").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.permitAll()
.and()
.logout()
.permitAll();
}
#Override
public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
resources.resourceId(RESOURCE_ID);
}
}
#Configuration
#EnableAuthorizationServer
protected static class AuthServer extends AuthorizationServerConfigurerAdapter {
#Autowired
#Qualifier("authenticationManagerBean")
private AuthenticationManager authenticationManager;
#Override
public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
oauthServer.allowFormAuthenticationForClients();
}
#Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.authenticationManager(authenticationManager);
}
#Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
.withClient("client")
.authorizedGrantTypes("password", "refresh_token")
.authorities("ROLE_USER")
.scopes("read")
.resourceIds(RESOURCE_ID)
.secret("secret").accessTokenValiditySeconds(3600);
}
}
}
The problem is I always get the following error when trying to open the home page ("/")
<oauth>
<error_description>
Full authentication is required to access this resource
</error_description>
<error>unauthorized</error>
</oauth>
It does not redirect to the login page.
I do not need this page to be protected by oauth2, but even if i go directly to the login page ("/login", which i can access) and supply credentials I still get the 'full authentication is required' error.
Even though i disabled basic http authentication.
Does anyone know how to separate the normal user UI from the api endpoints that need to be protected by OAuth2?
Can you try this
http
.authorizeRequests()
.antMatchers("/js/**", "/css/**", "/images/**", "/webjars/**", "/login").permitAll()
.antMatchers("/login").permitAll()
.antMatchers("/home").authenticated();
Considering /home is a page that needs to be authorized.
Hi you have to specify filters used for each config in your case you need:
in web security configurtion
http
.authorizeRequests()
.antMatchers("/api/**","/oauth/**")
.permitAll()
.and()
.......
this will let web security bypass authorization/resource servers URLs
and in resource server security configuration
http
.antMatcher("/api/**")
.authorizeRequests()
.anyRequest()
.authenticated();
this will let resource security bypass all URLs except "/api/**".
in this way you can ignore orders of configuration there is another option by make one of above actions and put its configuration in early order using #Order

Resources