RolesAllowed and antMatchers.hasRole are returning access denied caused by #Order - spring-boot

I restricted /api/topics and GET: /api/users to admins only and when I try to access them, I'm getting the following message:
{
"timestamp": "2020-04-05T09:26:49.938+0000",
"status": 403,
"error": "Forbidden",
"message": "Access Denied",
"path": "/api/topics"
}
It is caused by #Order(2) under WebSecurityConfiguration, but if I remove the #Order annotation, antMatchers.permitAll won't let me visit any REST endpoint without a token. That's the message:
{
"error": "unauthorized",
"error_description": "Full authentication is required to access this resource"
}
More information about #Order here. And you can check my previous thread on stackoverflow.
The order is totally messed up. Any ideas how to solve it?
It works if I do the following instead of antMatches.permitAll but then what is the point of permitAll and that entire http configuration?
#Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/api/topics/**");
}
Full code:
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(jsr250Enabled = true)
#Order(2)
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
#Bean
#Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.authorizeRequests()
.antMatchers("/api/topics/**").hasRole("ADMIN")
.antMatchers("/api/users/**").permitAll()
.anyRequest().authenticated();
}
#Bean
public BCryptPasswordEncoder bCryptPasswordEncoder() {
return new BCryptPasswordEncoder();
}
}
#Configuration
#EnableAuthorizationServer
public class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter {
#Autowired
private BCryptPasswordEncoder bCryptPasswordEncoder;
#Autowired
private TokenStore tokenStore;
#Autowired
private AuthenticationManager authenticationManager;
#Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients
.inMemory()
.withClient("trusted")
.secret(bCryptPasswordEncoder.encode("secret"))
.authorizedGrantTypes("password", "get_token", "refresh_token")
.scopes("read", "write")
.autoApprove(true)
.accessTokenValiditySeconds(15 * 60)
.refreshTokenValiditySeconds(30 * 60);
}
#Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints
.authenticationManager(authenticationManager)
.tokenStore(tokenStore);
}
#Bean
public TokenStore tokenStore() {
return new InMemoryTokenStore();
}
}
#Configuration
#EnableResourceServer
public class ResourceServerConfiguration {
}
// UserController.java
#RolesAllowed("ADMIN")
#GetMapping
public ResponseEntity<List<UserDTO>> getAll() {
return ResponseEntity.ok(userMapper.toUserDTOs(userService.getAll()));
}

You have to authenticated() after hasRole()
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.authorizeRequests()
.antMatchers("/api/topics/**").hasRole("ADMIN").authenticated() // You need to authenticate here
.antMatchers("/api/users/**").permitAll()
.anyRequest().authenticated();
}

Related

“error”: “invalid_grant”, “error_description”: “Bad credentials”

enter image description here
enter image description here
Photo 1: This is the error that appears in the postman when trying to validate
¨Photo 2 : In the Authorization I do not get the preview request
This is the code in Spring for the AuthorizationServerConfig class, code:
#Configuration
#EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter{
#Autowired
public BCryptPasswordEncoder passwordEncoder;
#Autowired
#Qualifier("authenticationManager")
private AuthenticationManager authenticationManager;
#Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.authenticationManager(authenticationManager)
.tokenStore(tokenStore())
.accessTokenConverter(accessTokenConverter());
}
#Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory().withClient("angularapp")
.secret(passwordEncoder.encode("12345"))
.scopes("read", "write")
.authorizedGrantTypes("password","refresh_token")
.accessTokenValiditySeconds(3600)
.refreshTokenValiditySeconds(3600);
}
#Override
public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
security.tokenKeyAccess("permitAll()")
.checkTokenAccess("isAuthenticated()");
}
#Bean
public JwtAccessTokenConverter accessTokenConverter() {
JwtAccessTokenConverter jwtAccessTokenConverter = new JwtAccessTokenConverter();
return jwtAccessTokenConverter;
}
#Bean
public JwtTokenStore tokenStore() {
return new JwtTokenStore(accessTokenConverter());
}
}
This is the ResourceServerCoonfig class in spring attached code just in case this error:
#Configuration
#EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter{
#Override
public void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().antMatchers(HttpMethod.GET,"/api/eventos").permitAll()
.anyRequest().authenticated();
}
}
and this is the code of the SpringSecurityConfig class, I also attach code:
#Configuration
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter{
#Autowired
private UserDetailsService usuarioService;
#Bean
public BCryptPasswordEncoder passwordEncoder(){
return new BCryptPasswordEncoder();
}
#Override
#Autowired
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(this.usuarioService).passwordEncoder(passwordEncoder());
}
#Bean("authenticationManager")
#Override
protected AuthenticationManager authenticationManager() throws Exception {
return super.authenticationManager(); //To change body of generated methods, choose Tools | Templates.
}
#Override
public void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.anyRequest().authenticated()
.and()
.csrf().disable()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
}
}
.secret("{bcrypt}$2a$10$kwz.jnLVLwJOYTAp2r/oG.8tfAN/EC5dK1w5beLgfpuFT6Puprgq.")
use something like this, spring security changed plain text passwords to bcrypt
Check here

How to permit endpoints in spring authorization server?

I have a spring boot oauth2 authorization server which will provide and authorize tokens. I also want to provide endpoints for user creation. Can you tell me how to permit these endpoints for non-authenticated users? I tried following configuration:
#Configuration
#EnableAuthorizationServer
#RequiredArgsConstructor
public class AuthorizationConfig extends AuthorizationServerConfigurerAdapter {
private TokenStore tokenStore = new InMemoryTokenStore();
private final UserDetailsService userDetailsServiceImpl;
private final AuthenticationManager authenticationManager;
private final PasswordEncoder passwordEncoder;
#Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
// TODO persist clients details
clients.inMemory()
.withClient("browser")
.authorizedGrantTypes("refresh_token", "password")
.scopes("ui");
}
#Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints
.tokenStore(tokenStore)
.authenticationManager(authenticationManager)
.userDetailsService(userDetailsServiceImpl);
}
#Override
public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
oauthServer
.tokenKeyAccess("permitAll()")
.checkTokenAccess("isAuthenticated()")
.passwordEncoder(passwordEncoder);
}
}
and authorization server configuration:
#Configuration
#EnableWebSecurity
#RequiredArgsConstructor
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
private final UserDetailsService userDetailsServiceImpl;
#Bean
PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
#Override
public void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests(authorizeRequests -> {
authorizeRequests
.antMatchers(HttpMethod.POST, "/user/**").permitAll()
.anyRequest().authenticated();
});
}
#Bean(name = "authenticationManager")
#Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.userDetailsService(userDetailsServiceImpl)
.passwordEncoder(passwordEncoder());
}
}
and here is endpoint which I want permit:
#RestController
#RequestMapping(path = "/user")
#RequiredArgsConstructor
public class UserController {
private final UserService userService;
#PostMapping
public UUID create(#RequestBody UserDto userDto) {
return userService.create(userDto);
}
}
With these configurations I always got response:
{
"timestamp": "2019-12-28T16:01:09.135+0000",
"status": 403,
"error": "Forbidden",
"message": "Forbidden",
"path": "/user"
}
I am using spring boot 2. Thank you in advice.
You need to disable CSRF in your AuthorizationConfig class. Try this configuration :
http.authorizeRequests(authorizeRequests -> {
authorizeRequests
.antMatchers(HttpMethod.POST, "/user/**").permitAll()
.anyRequest().authenticated();
}).csrf(csrf -> {
csrf.disable();
});
For more information about CSRF, check this website: https://www.owasp.org/index.php/Cross-Site_Request_Forgery_(CSRF).
Basically, you don't want to allow anybody to POST information on your website, so you allow to POST only if the user can provide a token indicating that he is using your website to POST (the token is provided by your server). In many web applications now, you can disable it, as you are POSTing from many locations... But don't forget the security of your website.

Spring OAuth2 "Full authentication is required to access this resource error" when trying to access login url

I am using Spring Security OAuth2 (Spring Boot 2.0.2 + Spring Cloud Finchley) and trying to initiate an implicit login. The browser redirects me to the /login URL but I get the the error "Full authentication is required to access this resource." How do I allow the login page to be displayed but still allow all REST urls to be secured?
My config is as follows:
App.java
#SpringBootApplication
#RestController
#EnableResourceServer
#EnableAuthorizationServer
public class App {
public static void main(String[] args) {
SpringApplication.run(App.class, args);
}
}
OAuth2Config.java
#Configuration
public class OAuth2Config extends AuthorizationServerConfigurerAdapter {
#Autowired
private AuthenticationManager authenticationManager;
#Autowired
private UserDetailsService userDetailsService;
#Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
.withClient("XXXXX")
.secret("XXXXX")
.authorizedGrantTypes("refresh_token", "password", "client_credentials")
.scopes("webclient", "mobileclient");
}
#Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints
.authenticationManager(authenticationManager)
.userDetailsService(userDetailsService);
}
}
WebSecurityConfigurer.java
#Configuration
#Order(-20) // EDIT
public class WebSecurityConfigurer extends WebSecurityConfigurerAdapter {
#Override
#Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
#Override
#Bean
public UserDetailsService userDetailsServiceBean() throws Exception {
return super.userDetailsServiceBean();
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
.withUser("XXXXX"). password("XXXXXX").roles("USER");
}
// EDIT
protected void configure(HttpSecurity http) throws Exception {
http.formLogin().permitAll()
.and().httpBasic().and()
.requestMatchers()
//specify urls handled
.antMatchers("/login", "/oauth/authorize", "/oauth/confirm_access")
.antMatchers("/fonts/**", "/js/**", "/css/**")
.and()
.authorizeRequests()
.antMatchers("/fonts/**", "/js/**", "/css/**").permitAll()
.anyRequest().authenticated();
}
}
}

Spring boot rest external tomcat 401 error

I have spring boot REST application that works perfectly fine when running on embedded tomcat. But as soon as I deploy it on external tomcat it gives 401 even for login requests
I followed https://www.mkyong.com/spring-boot/spring-boot-deploy-war-file-to-tomcat/ and was able to deploy on tomcat.
#SpringBootApplication
#EnableJpaAuditing
public class Application extends SpringBootServletInitializer {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(Application.class);
}
}
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
#Autowired
private EntryPointUnauthorizedHandler unauthorizedHandler;
#Autowired
private UserDetailsService userDetailsService;
#Autowired
private SecurityService securityService;
#Autowired
public void configureAuthentication(AuthenticationManagerBuilder authenticationManagerBuilder) throws Exception {
authenticationManagerBuilder
.userDetailsService(this.userDetailsService)
.passwordEncoder(passwordEncoder());
}
#Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
#Bean
#Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
#Bean
public AuthenticationTokenFilter authenticationTokenFilterBean() throws Exception {
AuthenticationTokenFilter authenticationTokenFilter = new AuthenticationTokenFilter();
authenticationTokenFilter.setAuthenticationManager(authenticationManagerBean());
return authenticationTokenFilter;
}
#Bean
public SecurityService securityService() {
return this.securityService;
}
#Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
httpSecurity
.csrf()
.disable()
.exceptionHandling()
.authenticationEntryPoint(this.unauthorizedHandler)
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
.antMatchers(HttpMethod.OPTIONS, "/**").permitAll()
.antMatchers("/auth/**").permitAll()
.anyRequest().authenticated()
.and()
.cors();
// Custom JWT based authentication
httpSecurity
.addFilterBefore(authenticationTokenFilterBean(), UsernamePasswordAuthenticationFilter.class);
}
}
Response on login
{
"timestamp": 1522175007525,
"status": 401,
"error": "Unauthorized",
"message": "Access Denied",
"path": "/test-app/api/auth"
}
I was able to solve the issue by changing the context path.
In application.properties file I have set
server.contextPath=/api
But it was totally ignored by tomcat and the final path changed from app/api/service to app/service
Rest all is working fine

Spring oauth2 basic authentication

I am trying to develop a rest api with spring security Using OAuth2 implementation. but how do I remove basic authentication. I just want to send a username and password to body and get a token on postman.
#Configuration
public class OAuthServerConfigration {
private static final String SERVER_RESOURCE_ID = "oauth2-server";
private static InMemoryTokenStore tokenStore = new InMemoryTokenStore();
#Configuration
#EnableResourceServer
protected static class ResourceServer extends ResourceServerConfigurerAdapter {
#Override
public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
resources.resourceId(SERVER_RESOURCE_ID).stateless(false);
}
#Override
public void configure(HttpSecurity http) throws Exception {
http.anonymous().disable().requestMatchers().antMatchers("/api/**").and().authorizeRequests().antMatchers("/api/**").access("#oauth2.hasScope('read')");
}
}
#Configuration
#EnableAuthorizationServer
protected static class AuthConfig extends AuthorizationServerConfigurerAdapter {
#Autowired
private AuthenticationManager authenticationManager;
#Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.authenticationManager(authenticationManager).tokenStore(tokenStore).approvalStoreDisabled();
}
#Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
.withClient("client")
.secret("$2a$10$5OkeCLKNs/BkdO0qcYRri.MdIcKhFvElAllhPgLfRQqG7wkEiPmq2")
.authorizedGrantTypes("password","authorization_code","refresh_token")
.authorities("ROLE_CLIENT", "ROLE_TRUSTED_CLIENT")
.scopes("read", "write", "trust")
.resourceIds(SERVER_RESOURCE_ID)
//.accessTokenValiditySeconds(ONE_DAY)
.accessTokenValiditySeconds(300)
.refreshTokenValiditySeconds(50);
}
#Override
public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
oauthServer
// we're allowing access to the token only for clients with 'ROLE_TRUSTED_CLIENT' authority
.tokenKeyAccess("hasAuthority('ROLE_TRUSTED_CLIENT')")
.checkTokenAccess("hasAuthority('ROLE_TRUSTED_CLIENT')");
}
}
}
#Configuration
#Order(2)
public static class ApiLoginConfig extends
WebSecurityConfigurerAdapter{
#Autowired
DataSource dataSource;
#Autowired
ClientDetailsService clientDetailsService;
#Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/oauth/**");
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.httpBasic().disable().csrf().disable().antMatcher("/oauth/token").authorizeRequests().anyRequest().permitAll();
}
#Override
#Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
#Bean
public TokenStore tokenStore() {
return new InMemoryTokenStore();
}
#Bean
#Autowired
public TokenStoreUserApprovalHandler userApprovalHandler(TokenStore tokenStore){
TokenStoreUserApprovalHandler handler = new TokenStoreUserApprovalHandler();
handler.setTokenStore(tokenStore);
handler.setRequestFactory(new DefaultOAuth2RequestFactory(clientDetailsService));
handler.setClientDetailsService(clientDetailsService);
return handler;
}
#Bean
#Autowired
public ApprovalStore approvalStore(TokenStore tokenStore) throws Exception {
TokenApprovalStore store = new TokenApprovalStore();
store.setTokenStore(tokenStore);
return store;
}
}
want to remove the basic authentication and send the username password in the body tag from the postman for get token
and I have got some problem
{
"error": "unauthorized",
"error_description": "There is no client authentication. Try adding an appropriate authentication filter."
}
In your #EnableAuthorizationServer configuration class in the method:-
#Override
public void configure(AuthorizationServerSecurityConfigurer oauthServer)
Try to add the following:-
oauthServer.allowFormAuthenticationForClients()
After you have done that you will have to call the oauth get token url as below:-
URL will be the same as http(s)://{HOST_NAME}/oauth/token
HTTP method type now will be POST
Header:-
Content-Type=application/x-www-form-urlencoded
Parameters will be key value pairs in x-www-form-urlencoded in the body of postman
for client_credentials grant_type:-
grant_type=client_credentials
client_id=client_id_value
client_secret=client_secret_value
scope=scopes
for password grant_type:-
grant_type=password
client_id=client_id_value
client_secret=client_secret_value
scope=scopes
username=username
password=password
scopes will be comma separated here

Resources