I'm trying to setup oauth with a Spring Boot rest api, but I'm getting a few problems.
When I try to get the Access Token via /auth/token I either get a 405 - Method Not Allowed:
Or the response from the base url (localhost:8080/) which is a simple json:
The first occurs when I don't define a PostMapping in the EntryController, the other occurs if I set it.
I also can see in the logs:
2018-09-10 22:03:16.011 INFO 78436 --- [on(3)-127.0.0.1] .s.o.p.e.FrameworkEndpointHandlerMapping : Mapped "{[/oauth/token],methods=[GET]}" onto public org.springframework.http.ResponseEntity<org.springframework.security.oauth2.common.OAuth2AccessToken> org.springframework.security.oauth2.provider.endpoint.TokenEndpoint.getAccessToken(java.security.Principal,java.util.Map<java.lang.String, java.lang.String>) throws org.springframework.web.HttpRequestMethodNotSupportedException
2018-09-10 22:03:16.012 INFO 78436 --- [on(3)-127.0.0.1] .s.o.p.e.FrameworkEndpointHandlerMapping : Mapped "{[/oauth/token],methods=[POST]}" onto public org.springframework.http.ResponseEntity<org.springframework.security.oauth2.common.OAuth2AccessToken> org.springframework.security.oauth2.provider.endpoint.TokenEndpoint.postAccessToken(java.security.Principal,java.util.Map<java.lang.String, java.lang.String>) throws org.springframework.web.HttpRequestMethodNotSupportedException
I've tried everything with no success.
This is the code I currently have:
Main:
@SpringBootApplication
@PropertySource("classpath:application.properties")
public class Main extends SpringBootServletInitializer {
public static void main(String[] args) {
SpringApplication.run(Main.class, args);
}
}
WebServerConfiguration:
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
@Autowired
private UserDetailsService userDetailsService;
@Bean
public PasswordEncoder passwordEncoder() {
return PasswordEncoderFactories.createDelegatingPasswordEncoder();
}
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Override
public void configure(HttpSecurity http) throws Exception {
http.csrf().disable().exceptionHandling()
.authenticationEntryPoint(
(request, response, authException) -> response.sendError(HttpServletResponse.SC_UNAUTHORIZED)
)
.and()
.authorizeRequests().anyRequest().authenticated()
.and()
.httpBasic();
}
@Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
}
}
OAuth2Configuration:
@Configuration
@EnableAuthorizationServer
public class OAuth2Configuration extends AuthorizationServerConfigurerAdapter {
@Value("${check-user-scopes}")
private Boolean checkUserScopes;
@Value("${security.signing-key}")
private String signingKey;
@Autowired
private DataSource dataSource;
@Autowired
private PasswordEncoder passwordEncoder;
@Autowired
private UserDetailsService userDetailsService;
@Autowired
private ClientDetailsService clientDetailsService;
@Autowired
@Qualifier("authenticationManagerBean")
private AuthenticationManager authenticationManager;
@Bean
public OAuth2RequestFactory requestFactory() {
CustomOauth2RequestFactory requestFactory = new CustomOauth2RequestFactory(clientDetailsService);
requestFactory.setCheckUserScopes(true);
return requestFactory;
}
@Bean
public TokenStore tokenStore() {
return new JwtTokenStore(jwtAccessTokenConverter());
}
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.jdbc(dataSource).passwordEncoder(passwordEncoder);
}
@Bean
public TokenEndpointAuthenticationFilter tokenEndpointAuthenticationFilter() {
return new TokenEndpointAuthenticationFilter(authenticationManager, requestFactory());
}
@Override
public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
oauthServer.tokenKeyAccess("permitAll()").checkTokenAccess("isAuthenticated()");
}
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints
.tokenStore(tokenStore())
.tokenEnhancer(jwtAccessTokenConverter())
.authenticationManager(authenticationManager)
.userDetailsService(userDetailsService);
if (checkUserScopes)
endpoints.requestFactory(requestFactory());
}
@Bean
public JwtAccessTokenConverter jwtAccessTokenConverter() {
JwtAccessTokenConverter converter = new CustomTokenEnhancer();
/*converter.setKeyPair(
new KeyStoreKeyFactory(new ClassPathResource("jwt.jks"), "password".toCharArray()).getKeyPair("jwt"));*/
converter.setSigningKey(signingKey);
return converter;
}
/*
* Add custom user principal information to the JWT token
*/
class CustomTokenEnhancer extends JwtAccessTokenConverter {
@Override
public OAuth2AccessToken enhance(OAuth2AccessToken accessToken, OAuth2Authentication authentication) {
User user = (User) authentication.getPrincipal();
Map<String, Object> info = new LinkedHashMap<>(accessToken.getAdditionalInformation());
info.put("email", user.getEmail());
DefaultOAuth2AccessToken customAccessToken = new DefaultOAuth2AccessToken(accessToken);
customAccessToken.setAdditionalInformation(info);
return super.enhance(customAccessToken, authentication);
}
}
class CustomOauth2RequestFactory extends DefaultOAuth2RequestFactory {
@Autowired
private TokenStore tokenStore;
public CustomOauth2RequestFactory(ClientDetailsService clientDetailsService) {
super(clientDetailsService);
}
@Override
public TokenRequest createTokenRequest(Map<String, String> requestParameters,
ClientDetails authenticatedClient) {
if (requestParameters.get("grant_type").equals("refresh_token")) {
OAuth2Authentication authentication = tokenStore.readAuthenticationForRefreshToken(
tokenStore.readRefreshToken(requestParameters.get("refresh_token")));
SecurityContextHolder.getContext()
.setAuthentication(new UsernamePasswordAuthenticationToken(authentication.getName(), null,
userDetailsService.loadUserByUsername(authentication.getName()).getAuthorities()));
}
return super.createTokenRequest(requestParameters, authenticatedClient);
}
}
}
ResourceServerConfiguration:
@Configuration
@EnableResourceServer
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {
@Autowired
public TokenStore tokenStore;
@Override
public void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().anyRequest().authenticated().and().cors().disable().csrf().disable().httpBasic().disable()
.exceptionHandling()
.authenticationEntryPoint(
(request, response, authException) -> response.sendError(HttpServletResponse.SC_UNAUTHORIZED))
.accessDeniedHandler(
(request, response, authException) -> response.sendError(HttpServletResponse.SC_UNAUTHORIZED));
}
@Override
public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
resources.resourceId("mw/client").tokenStore(tokenStore);
}
}
UPDATE
The controller that is triggering the differences is:
@RestController
public class EntryController {
@RequestMapping/*(method = RequestMethod.GET)*/
public ResponseEntity<String> entry() {
final HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.setContentType(MediaType.APPLICATION_JSON);
return new ResponseEntity<>("{\"msg\": \"Hello World\"}", httpHeaders, HttpStatus.OK);
}
}
If set with RequestMapping I get the Hello World json, if set to Get only I get the 405.
Also I forgot to mention that I'm deploying the application to Tomcat through a war file.
Any help would be appreciated.
Thanks in advance
If you are using @RequestMapping then you need to pass both Path and method like below
@RequestMapping(value = "/v1/hello", method = RequestMethod.GET)
public ResponseEntity<String> entry() {
final HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.setContentType(MediaType.APPLICATION_JSON);
return new ResponseEntity<>("{\"msg\": \"Hello World\"}", httpHeaders,
HttpStatus.OK);
}
if you want to use directly @PostMapping, @GetMapping etc then just path is required like this
@GetMapping(value = "/v1/hello")
public ResponseEntity<String> entry() {
final HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.setContentType(MediaType.APPLICATION_JSON);
return new ResponseEntity<>("{\"msg\": \"Hello World\"}", httpHeaders,
HttpStatus.OK);
}
so use accordingly then check as 405 means api signature does not met with any Rest controller apis you have defined.
let me after correct controller you face any issue.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.