couldn't find a doc which illustrates how to use access_token to get user info.
How can I make a such endpoint?
I see when I access the /user endpoint OAuth2AuthenticationProcessingFilter is not included.
I think I messed up something below
#Configuration
#EnableWebSecurity
#Order(2)
// after ResourceServerConfigurerAdapter
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
// https://stackoverflow.com/questions/26387003/how-to-make-spring-boot-never-issue-session-cookie
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
.authorizeRequests()
.antMatchers("/", "index", "/login**", "/webjars/**")
.permitAll()
.and().exceptionHandling()
.authenticationEntryPoint(authenticationEntryPoint)
.accessDeniedHandler(oAuth2FailedHandler)
.and().csrf().disable().authorizeRequests()
.and().addFilterBefore(new CORSFilter(), BasicAuthenticationFilter.class); }
}
I also have..
#Order(3)
#Configuration
#EnableResourceServer
#Slf4j
public class OAuth2ResourceServerConfig extends ResourceServerConfigurerAdapter {
#Override
public void configure(final ResourceServerSecurityConfigurer config) {
config.tokenServices(tokenServices());
}
#Override
public void configure(HttpSecurity http) throws Exception {
// super.configure(http);
log.info("hello OAuth2ResourceServerConfig:configure");
http
.authorizeRequests().anyRequest().authenticated();
}
#Bean
#Primary
public DefaultTokenServices tokenServices() {
final DefaultTokenServices defaultTokenServices = new DefaultTokenServices();
defaultTokenServices.setTokenStore(tokenStore());
return defaultTokenServices;
}
// JDBC token store configuration
#Bean
public DataSource dataSource() {
final DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName(env.getProperty("spring.datasource.driver-class-name"));
dataSource.setUrl(env.getProperty("spring.datasource.url"));
dataSource.setUsername(env.getProperty("spring.datasource.username"));
dataSource.setPassword(env.getProperty("spring.datasource.password"));
return dataSource;
}
#Bean
public TokenStore tokenStore() {
return new JdbcTokenStore(dataSource());
}
}
#Configuration
//#PropertySource({ "classpath:persistence.properties" }) #EnableAuthorizationServer
#Slf4j
public class OAuth2AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
// ....
}
Add a REST controller with something like this:
#RequestMapping("/user")
public #ResponseBody Principal user(Principal user) {
return user;
}
Then you can call it, using your access token in the Authorization header.
Related
My configuration for the Spring Boot resource server is provided:
#Configuration
public class OAuth2SecurityConfig extends WebSecurityConfigurerAdapter {
#Bean
#Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
#Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
#Configuration
#EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
private static final String RESOURCE_ID = "couponservice";
#Override
public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
resources.resourceId(RESOURCE_ID);
}
#Override
public void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.mvcMatchers(HttpMethod.GET, "/couponapi/coupons/{code:^[A-Z]*$}").hasAnyRole("USER", "ADMIN")
.mvcMatchers(HttpMethod.POST, "/couponapi/coupons").hasRole("ADMIN")
.anyRequest().denyAll().and().csrf().disable();
}
// #Bean
// public TokenStore tokenStore() {
// return new JwtTokenStore(jwtAccessTokenConverter());
// }
//
// #Bean
// public JwtAccessTokenConverter jwtAccessTokenConverter() {
//
// JwtAccessTokenConverter jwtAccessTokenConverter = new JwtAccessTokenConverter();
// jwtAccessTokenConverter.setVerifierKey(publicKey);
//
// return jwtAccessTokenConverter;
// }
}
The application.properties file is provided:
spring.datasource.url=jdbc:mysql://localhost:3306/mydb
spring.datasource.username=testuser
spring.datasource.password=testpassword
server.port=9091
spring.thymeleaf.cache=false
spring.main.allow-bean-definition-overriding=true
spring.security.oauth2.resourceserver.jwt.jwk-set-uri=http://localhost:9092/oauth/token_key
# security.oauth2.resource.jwt.key-uri=http://localhost:9092/oauth/token_key
If I keep the JwtAccessTokenConverter and use the correct public key, the code is working. But, I would like to connect using the auth URL provided in the properties files.
Now, when I make the GET request, I see the invalid access toekn. Whats the issue here and how do I resolve it?
Looks like you need to tell Spring WHAT MECHANISM to use to authorize. Maybe compare to this Curity example, which should provide enough clues to overcome your problem:
Code
Configuration
#EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
#Value("${spring.security.oauth2.resourceserver.jwt.issuer-uri}")
String issuerUri;
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests(authorizeRequests ->
authorizeRequests
.antMatchers("/services").hasAuthority("SCOPE_services:read")
.anyRequest().authenticated()
)
.oauth2ResourceServer(oauth2ResourceServer ->
oauth2ResourceServer
.jwt(jwt ->
jwt.decoder(JwtDecoders.fromIssuerLocation(issuerUri))
)
);
}
}
I have obtained the access token using appropriate endpoint using okta. using the obtained access token i am trying to make a REST call by passing access token as Authorization Header type Bearer. but getting 401 unauthorized error with the following error message
"Full authentication is required to access this resource"
AuthorizationServerConfig.java
#Configuration
#EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
static final String CLIENT_SECRET = "fXMuUOUo31nNlbnnjn64019h3JP-s6VZEOV4VGW1";
static final String CLIENT_ID = "0oaz4m4njwGDMqXB1356";
#Autowired
private TokenStore tokenStore;
#Autowired
private AuthenticationManager authenticationManager;
#Override
public void configure(ClientDetailsServiceConfigurer configurer) throws Exception {
configurer.inMemory()
.withClient(CLIENT_ID)
.secret(CLIENT_SECRET)
.authorizedGrantTypes(new String[] { "password", "refresh_token", "authorization_code" })
.accessTokenValiditySeconds(3600)
.refreshTokenValiditySeconds(3600);
}
#Bean
public TokenStore tokenStore() {
return new JwtTokenStore(accessTokenConverter());
}
#Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.tokenStore(tokenStore)
.authenticationManager(authenticationManager)
.accessTokenConverter(accessTokenConverter());
}
#Bean
public JwtAccessTokenConverter accessTokenConverter() {
JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
converter.setSigningKey("as466gf");
return converter;
}
/**
* Bean for Token Servers Primary is added as there are three token services in the classpath
*
* #return DefaultTokenServices Default Token Service
*/
#Bean
#Primary
public DefaultTokenServices tokenServices() {
DefaultTokenServices defaultTokenServices = new DefaultTokenServices();
defaultTokenServices.setTokenStore(tokenStore());
defaultTokenServices.setSupportRefreshToken(true);
return defaultTokenServices;
}
}
ResourceServerConfig.java
#Configuration
#EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
#Override
public void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/user/authenticate/**").permitAll()
.antMatchers("/user/greet/**").permitAll()
.antMatchers("/user/getRefreshedTokens/**").permitAll()
.anyRequest().authenticated()
.and()
.httpBasic();
}
#Override
public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
resources.resourceId("ResourceId");
}
}
SecurityConfig.java
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
/**
* OAuth ignores the configuration below
*
* #See ResourceServerConfig to control Authorization
*/
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/user/authenticate/**").permitAll()
.antMatchers("/user/greet/**").permitAll()
.antMatchers("/user/getRefreshedTokens/**").permitAll()
.anyRequest().authenticated()
.and()
.httpBasic();
}
#Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
#Bean
#Override
protected AuthenticationManager authenticationManager() throws Exception {
return super.authenticationManager();
}
}
Is it possible to implement OAuth implicit flow with spring security? I want to create both auth and resource server in the same application. I need standard auth endpoints for authentication and authorization and some custom endpoints for handling with users (create/update/list...).
Requirements:
implicit flow
custom login page (/my_login_page)
silent mode for obtaining token (/oauth/authorize?...&prompt=none)
secured custom endpoints with OAuth (/users)
I'm stuck with configuration. Whatever I do, the requirements above never work together.
Spring WebSecurityConfig
#Configuration
#Order(-10)
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
private MyAuthenticationProvider authenticationProvider;
private MyAuthenticationDetailsSource authenticationDetailsSource;
#Autowired
public SecurityConfig(MyAuthenticationProvider authenticationProvider, MyAuthenticationDetailsSource authenticationDetailsSource) {
this.authenticationProvider = authenticationProvider;
this.authenticationDetailsSource = authenticationDetailsSource;
}
#Bean
#Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.authenticationProvider(authenticationProvider);
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.NEVER)
.sessionFixation().newSession()
.and()
.authorizeRequests()
.antMatchers("/assets/**", "/swagger-ui.html", "/webjars/**", "/swagger-resources/**", "/v2/**").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/my_login_page")
.loginProcessingUrl("/my_process_login")
.usernameParameter("my_username")
.passwordParameter("pmy_assword")
.authenticationDetailsSource(authenticationDetailsSource)
.permitAll();
}
}
Spring AuthorizationServerConfig
#Configuration
#EnableAuthorizationServer
public class OAuth2AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
private ResourceLoader resourceLoader;
private AuthProps authProps;
#Autowired
public OAuth2AuthorizationServerConfig(ResourceLoader resourceLoader, AuthProps authProps) {
this.resourceLoader = resourceLoader;
this.authProps = authProps;
}
#Bean
public TokenStore tokenStore() {
return new JwtTokenStore(accessTokenConverter());
}
#Bean
#Qualifier("jwtAccessTokenConverter")
public JwtAccessTokenConverter accessTokenConverter() {
KeyStoreKeyFactory keyStoreKeyFactory = new KeyStoreKeyFactory(resourceLoader.getResource(authProps.getAuthServerPrivateCertPath()), authProps.getAuthServerPrivateCertKey().toCharArray());
JwtAccessTokenConverter converter = new MYJwtAccessTokenConverter();
converter.setKeyPair(keyStoreKeyFactory
.getKeyPair(authProps.getAuthServerPrivateCertAlias()));
final Resource resource = resourceLoader.getResource(authProps.getAuthServerPublicCertPath());
String publicKey;
try {
publicKey = IOUtils.toString(resource.getInputStream());
} catch (final IOException e) {
throw new RuntimeException(e);
}
converter.setVerifierKey(publicKey);
return converter;
}
#Bean
#Primary
public DefaultTokenServices tokenServices() {
DefaultTokenServices defaultTokenServices = new DefaultTokenServices();
defaultTokenServices.setTokenStore(tokenStore());
return defaultTokenServices;
}
#Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) {
endpoints
.tokenStore(tokenStore())
.accessTokenConverter(accessTokenConverter());
}
#Override
public void configure(AuthorizationServerSecurityConfigurer oauthServer) {
oauthServer
.tokenKeyAccess("permitAll()")
.checkTokenAccess("isAuthenticated()");
}
#Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
.withClient("my-secured-client")
.secret("foo")
.authorizedGrantTypes("implicit")
.scopes("read", "write")
.resourceIds("my-resource")
.authorities("CLIENT")
.redirectUris(
"http://localhost:4200"
)
.accessTokenValiditySeconds(300)
.autoApprove(true);
}
}
Spring ResourceServerConfig
#Configuration
#EnableResourceServer
public class OAuth2ResourceServerConfig extends ResourceServerConfigurerAdapter {
private AuthProps authProps;
private TokenStore tokenStore;
private DefaultTokenServices tokenServices;
#Autowired
public OAuth2ResourceServerConfig(AuthProps authProps, TokenStore tokenStore, DefaultTokenServices tokenServices) {
this.authProps = authProps;
this.tokenStore = tokenStore;
this.tokenServices = tokenServices;
}
#Override
public void configure(final ResourceServerSecurityConfigurer config) {
config
.resourceId("my-resource")
.tokenStore(tokenStore)
.tokenServices(tokenServices);
}
#Override
public void configure(final HttpSecurity http) throws Exception {
http
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
.antMatchers(HttpMethod.OPTIONS).permitAll()
.antMatchers("/**").authenticated()
.and()
.csrf().disable();
}
}
I placed WebSecurityConfig before ResourceServerConfig otherwise login page doesn't work. But now I can't access my custom endpoint for users (I'm redirected to the login page). If I place ResourceServerConfig before WebSecurityConfig login page stop working. I get 404 not found response when I submit login page form.
I also have an issue with silent mode to obtain a new access token. When calling /oauth/authorize with still valid access_token I'm redirected to the login page.
Finally I found a solution:
ResourceServerConfig have to be before WebSecurityConfig
loginProcessingUrl should be /oauth/authorize
Silent refresh works by default until session is valid (login form)
Custom endpoint for logout where invalidate current session
EDITED:
#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
private MyAuthenticationProvider authenticationProvider;
private MyAuthenticationDetailsSource authenticationDetailsSource;
#Autowired
public SecurityConfig(MyAuthenticationProvider authenticationProvider, MyAuthenticationDetailsSource authenticationDetailsSource) {
this.authenticationProvider = authenticationProvider;
this.authenticationDetailsSource = authenticationDetailsSource;
}
#Bean
#Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
#Override
protected void configure(AuthenticationManagerBuilder auth) {
auth
.authenticationProvider(authenticationProvider);
}
#Override
public void configure(WebSecurity web) {
web
.debug(true)
.ignoring()
.antMatchers(HttpMethod.OPTIONS)
.antMatchers("/my-custom-login-page", "/my-custom-logout-page")
.antMatchers("/assets/**", "/swagger-ui.html", "/webjars/**", "/swagger-resources/**", "/v2/**");
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED)
.and()
.authorizeRequests()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/my-custom-login-page")
.loginProcessingUrl("/oauth/authorize")
.usernameParameter("myUsernameParam")
.passwordParameter("myPasswordParam")
.authenticationDetailsSource(authenticationDetailsSource)
.permitAll()
.and()
.csrf().disable();
}
}
#Configuration
#EnableAuthorizationServer
public class OAuth2AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
private ResourceLoader resourceLoader;
private AuthProps authProps;
#Autowired
public OAuth2AuthorizationServerConfig(ResourceLoader resourceLoader, AuthProps authProps) {
this.resourceLoader = resourceLoader;
this.authProps = authProps;
}
#Bean
public TokenStore tokenStore() {
return new JwtTokenStore(accessTokenConverter());
}
#Bean
#Qualifier("jwtAccessTokenConverter")
public JwtAccessTokenConverter accessTokenConverter() {
KeyStoreKeyFactory keyStoreKeyFactory = new KeyStoreKeyFactory(resourceLoader.getResource(authProps.getAuthServerPrivateCertPath()), authProps.getAuthServerPrivateCertKey().toCharArray());
JwtAccessTokenConverter converter = new MyJwtAccessTokenConverter();
converter.setKeyPair(keyStoreKeyFactory.getKeyPair(authProps.getAuthServerPrivateCertAlias()));
final Resource resource = resourceLoader.getResource(authProps.getAuthServerPublicCertPath());
String publicKey;
try {
publicKey = IOUtils.toString(resource.getInputStream());
} catch (final IOException e) {
throw new RuntimeException(e);
}
converter.setVerifierKey(publicKey);
return converter;
}
#Bean
#Primary
public DefaultTokenServices tokenServices() {
DefaultTokenServices defaultTokenServices = new DefaultTokenServices();
defaultTokenServices.setTokenStore(tokenStore());
return defaultTokenServices;
}
#Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) {
endpoints
.tokenStore(tokenStore())
.accessTokenConverter(accessTokenConverter());
}
#Override
public void configure(AuthorizationServerSecurityConfigurer oauthServer) {
oauthServer
.tokenKeyAccess("permitAll()")
.checkTokenAccess("isAuthenticated()");
}
#Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
.withClient(authProps.getAuthServerClientId())
.secret(authProps.getAuthServerClientSecret())
.authorizedGrantTypes("implicit")
.scopes("read", "write")
.resourceIds(authProps.getAuthServerResourceId())
.authorities("CLIENT")
.redirectUris(
"http://localhost:4200/#/login",
"http://localhost:4200/assets/silent-refresh.html",
"http://localhost:8080/my-api/webjars/springfox-swagger-ui/oauth2-redirect.html"
)
.accessTokenValiditySeconds(authProps.getAuthServerAccessTokenValiditySeconds())
.autoApprove(true);
}
}
#Configuration
#EnableResourceServer
public class OAuth2ResourceServerConfig extends ResourceServerConfigurerAdapter {
private AuthProps authProps;
private TokenStore tokenStore;
private DefaultTokenServices tokenServices;
#Autowired
public OAuth2ResourceServerConfig(AuthProps authProps, TokenStore tokenStore, DefaultTokenServices tokenServices) {
this.authProps = authProps;
this.tokenStore = tokenStore;
this.tokenServices = tokenServices;
}
#Override
public void configure(final ResourceServerSecurityConfigurer config) {
config.resourceId(authProps.getAuthServerResourceId()).tokenStore(tokenStore);
config.resourceId(authProps.getAuthServerResourceId()).tokenServices(tokenServices);
}
#Override
public void configure(final HttpSecurity http) throws Exception {
http
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
.anyRequest().hasRole(AppRole.ROLE_APP_USER.split("ROLE_")[1])
.and()
.csrf().disable();
}
}
#Controller
public class MainController {
#Autowired
public MainController() {
...
}
#GetMapping("/my-custom-login-page")
public ModelAndView loginPage(HttpServletRequest request, HttpServletResponse response) {
ModelAndView mv = new ModelAndView("login-page");
return mv;
}
#GetMapping("/my-custom-logout-page")
public ModelAndView logoutPage(HttpServletRequest request) {
ModelAndView mv = new ModelAndView("logout-page");
HttpSession session = request.getSession(false);
if (Objects.isNull(session)) {
mv.addObject("msg", "NO SESSION");
return mv;
}
session.invalidate();
mv.addObject("msg", "SUCCEEDED");
return mv;
}
}
In addition to #user3714967 answer, I add some tips maybe It helps someone. The problem is that we are defining multiple HttpSecurity (The resourceServer is a WebSecurityConfigurerAdapter with order 3). The solution is to use HttpSecurity.requestMatchers() with the specific value.
Example
First Class:
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.requestMatchers().antMatchers("url1", "url2", ...).and()
.authorizeRequests()
.antMatchers(...).and()...
}
}
Second Class:
#Configuration
#EnableResourceServer
public class OAuth2ResourceServerConfig extends ResourceServerConfigurerAdapter {
#Override
public void configure(HttpSecurity http) throws Exception {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.requestMatchers().antMatchers("url3", "url4", ...)
.and()
.authorizeRequests()
.antMatchers(...).and()...
}
}
}
This will be useful when we have more than flow (password && implicit flows for my case).
I need to add OAuth2 security using an ldap authentication.
I have first implemented ldap authenication and add a WebSecurityConfigurerAdapter instance.
#Configuration
#EnableWebSecurity
#Order(2)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(final HttpSecurity http) throws Exception {
http.authorizeRequests()
.anyRequest().fullyAuthenticated()
.and()
.formLogin();
}
#Override
#Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
#Autowired
public void configureGlobal(final AuthenticationManagerBuilder auth) throws Exception {
auth.ldapAuthentication()
.contextSource().url("ldaps://master:636/dc=domain,dc=com")
.managerDn("cn=readonly,dc=domain,dc=com").managerPassword("123456")
.and()
.userSearchFilter("(uid={0})");
}
}
I need to add OAuth2 resource server adapter ResourceServerConfigurerAdapter
#Configuration
#Import({ DatabaseConfig.class })
#EnableResourceServer
#Order(1)
public class OAuth2ResourceServerConfig extends ResourceServerConfigurerAdapter {
#Autowired DatabaseConfig databaseConfig;
#Override
public void configure(final HttpSecurity http) throws Exception {
http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED).and().authorizeRequests()
.anyRequest().authenticated();
}
#Bean
public JwtAccessTokenConverter accessTokenConverter() {
final JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
// converter.setSigningKey("123");
final Resource resource = new ClassPathResource("public.txt");
String publicKey = null;
try {
publicKey = IOUtils.toString(resource.getInputStream());
} catch (final IOException e) {
throw new RuntimeException(e);
}
converter.setVerifierKey(publicKey);
return converter;
}
#Bean
#Primary
public DefaultTokenServices tokenServices() {
final DefaultTokenServices defaultTokenServices = new DefaultTokenServices();
defaultTokenServices.setTokenStore(tokenStore());
return defaultTokenServices;
}
#Bean
public TokenStore tokenStore() {
return new JdbcTokenStore(databaseConfig.dataSource());
}
It seems like WebSecurityConfigurerAdapter and ResourceServerConfigurerAdapter conflicting when both configured.
I am playing with both configure() method but I can only get an access login through ldap using http://localhost:8080/login on my Rest API, and couldn't using my angular client using oauth http://localhost:8081/login
I have the following error when trying to access the resource:
Failed to find refresh token for token eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX25hbWUiOiJqb2huIiwic2NvcGUiOlsiZm9vIiwicmVhZCIsIndyaXRlIl0sIm9yZ2FuaXphdGlvbiI6ImpvaG5vRnZiIiwiYXRpIjoiNDcyZTJiNDYtZjgxZS00NGJiLWEwNDMtMGYwZmRjMDMzY2U1IiwiZXhwIjoxNDc2NTQ5NjYzLCJhdXRob3JpdGllcyI6WyJST0xFX1VTRVIiXSwianRpIjoiN2UwNzRkZDktOWI0ZC00MTU0LWJjMzktMDlkY2U4Y2UyZTg2IiwiY2xpZW50X2lkIjoiZm9vQ2xpZW50SWRQYXNzd29yZCJ9.fuarTPL1O00Yg6b3BPibwux1ZtlmrHaPCJkgjsJni_51B3NEHkdB9kqbABK3IkMWMlZdqY8xfR-zMpY9SxFkpRFDfyvosgLcsTZ...
Handling error: InvalidGrantException, Invalid refresh token: eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVC...
I have the same issue. May be my solution is not graceful, but it works for me.
I had tried OAuth2ResourceServerConfig which extends WebSecurityConfig and implements ResourceServerConfigurer.
Your OAuth2ResourceServerConfig must be like this
#Configuration
#Import({ DatabaseConfig.class })
#EnableResourceServer
#Order(1)
public class OAuth2ResourceServerConfig extends WebSecurityConfig implements ResourceServerConfigurer {
#Autowired DatabaseConfig databaseConfig;
#Override
public void configure(final HttpSecurity http) throws Exception {
http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED).and().authorizeRequests()
.anyRequest().authenticated();
}
#Bean
public JwtAccessTokenConverter accessTokenConverter() {
final JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
// converter.setSigningKey("123");
final Resource resource = new ClassPathResource("public.txt");
String publicKey = null;
try {
publicKey = IOUtils.toString(resource.getInputStream());
} catch (final IOException e) {
throw new RuntimeException(e);
}
converter.setVerifierKey(publicKey);
return converter;
}
#Bean
#Primary
public DefaultTokenServices tokenServices() {
final DefaultTokenServices defaultTokenServices = new DefaultTokenServices();
defaultTokenServices.setTokenStore(tokenStore());
return defaultTokenServices;
}
#Bean
public TokenStore tokenStore() {
return new JdbcTokenStore(databaseConfig.dataSource());
}
According this post, I think you can use the previous version by adding this to you config(yml or properties):
security:
oauth2:
resource:
filter-order: 3
And I tried adding #Order annotation to my source server config as you did, and get the same issue. So, I think #Order annotation doesn't take effect to ResourceServerConfigurerAdapter, but it works fine with WebSecurityConfig. I don't know is it a bug or intended.
i am working in a personal project and i using spring web mvc and spring security 4, all annotation based configs, and my custom UsernamePasswordAuthenticationFilter is never reached, i am losing it, i already search but i can get it solved, so if anyone could help, i 'd be very grateful, So here is my code
Spring Initialization
#Order(1)
public class SpringMvcInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
#Override
protected Class<?>[] getRootConfigClasses() {
return new Class[]{AppConfig.class};
}
#Override
protected Class<?>[] getServletConfigClasses() {
return null;
}
#Override
protected String[] getServletMappings() {
return new String[]{"/"};
}
}
Security Initialization
#Order(2)
public class SecurityInitializer extends AbstractSecurityWebApplicationInitializer {
}
Spring beans declarations and context stuff
#EnableWebMvc
#Configuration
#ComponentScan({"app","server"})
#Import({ SecurityContext.class })
public class AppConfig extends WebMvcConfigurerAdapter {
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/**").addResourceLocations("/META-INF/resources/");
}
#Bean
public InternalResourceViewResolver viewResolver(){
InternalResourceViewResolver resolver = new InternalResourceViewResolver();
resolver.setSuffix(".jsp");
resolver.setPrefix("/WEB-INF/views/");
resolver.setContentType("text/html; charset=UTF-8");
resolver.setViewClass(JstlView.class);
return resolver;
}
#Bean
public DriverManagerDataSource dataSource(){
DriverManagerDataSource driver = new DriverManagerDataSource();
driver.setDriverClassName("com.mysql.jdbc.Driver");
driver.setUrl("jdbc:mysql://localhost:3306/dberp-1");
driver.setUsername("root");
driver.setPassword("123456");
return driver;
}
#Bean
public LocalSessionFactoryBean sessionFactory(){
LocalSessionFactoryBean session = new LocalSessionFactoryBean();
session.setDataSource(dataSource());
String[] pakages = {"model"};
session.setPackagesToScan(pakages);
Properties prop = new Properties();
prop.put("dialect", MySQLDialect.class);
session.setHibernateProperties(prop);
return session;
}
}
I am almost sure i am doing something wrong in this SecurityContext class....
#Configuration
#EnableWebSecurity
public class SecurityContext extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception{
http
.exceptionHandling()
.authenticationEntryPoint(authenticationEntryPoint())
.and()
.addFilterBefore(authenticationFilter(), UsernamePasswordAuthenticationFilter.class)
.authorizeRequests()
.antMatchers("/login","/resources/**").anonymous()
.antMatchers("/users").hasAuthority("admin")
.antMatchers("/**").hasAnyAuthority("employee","admin")
.and()
.logout()
.logoutSuccessUrl("/login")
.invalidateHttpSession(true)
.logoutUrl("/logout")
.and()
.csrf().disable();
}
#Bean
public AuthenticationEntryPoint authenticationEntryPoint(){
AuthenticationEntryPoint entryAuth = new LoginUrlAuthenticationEntryPoint("/login");
return entryAuth;
}
#Bean(name="customAuthenticationManager")
#Override
protected AuthenticationManager authenticationManager() throws Exception {
AuthenticationManager authManager = new CustomAuthenticationManager();
return authManager;
};
#Bean
public UsernamePasswordAuthenticationFilter authenticationFilter() throws Exception{
/*UsernamePasswordAuthenticationFilter authFilter = new UsernamePasswordAuthenticationFilter();
authFilter.setAuthenticationManager(authenticationManager());
authFilter.setAuthenticationSuccessHandler(new SimpleUrlAuthenticationSuccessHandler("/home"));
authFilter.setAuthenticationFailureHandler(new SimpleUrlAuthenticationFailureHandler("/login?error"));*/
UsernamePasswordAuthenticationFilter authFilter = new AuthFilter();
authFilter.setAuthenticationManager(authenticationManager());
authFilter.setAuthenticationSuccessHandler(new SimpleUrlAuthenticationSuccessHandler("/home"));
authFilter.setAuthenticationFailureHandler(new SimpleUrlAuthenticationFailureHandler("/login?error"));
authFilter.setRequiresAuthenticationRequestMatcher(new AntPathRequestMatcher("/login", "POST"));
return authFilter;
}
}