Oauth2 Resource server overlap Spring Security configuration - java

I am trying to configure Spring Security and OAuth2 on java config. I am using Spring Security version 4.0.4.RELEASE and OAuth2 version 2.0.11.RELEASE.
Spring Security config works well. Also I can get an access token with OAuth2 AuthorizationServer, but my ResourceServer does not work correctly. When I set the annotation #EnableResourceServer I can only check my access token and other URLs I cannot open (Security configuration and AuthorizationServer configuration do not work). I see the following error:
<oauth>
<error_description>
An Authentication object was not found in the SecurityContext
</error_description>
<error>unauthorized</error>
</oauth>
If I remove an annotation #EnableResourceServer, my ResourceServer does not check an access token. It just redirects to the authentication page.
This is my code:
#Configuration
#EnableGlobalMethodSecurity(prePostEnabled = true, proxyTargetClass = true)
public class GlobalSecurityConfig extends GlobalMethodSecurityConfiguration {
#Bean(name = "passwordEncoder")
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
#Autowired
#Qualifier("authUserDetailsService")
private UserDetailsService userDetailsService;
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth
.userDetailsService(userDetailsService)
.passwordEncoder(passwordEncoder());
}
#Autowired
#Qualifier("permissionEvaluator")
private PermissionEvaluator permissionEvaluator;
#Bean
public DefaultMethodSecurityExpressionHandler expressionHandler() {
DefaultMethodSecurityExpressionHandler handler = new DefaultMethodSecurityExpressionHandler();
handler.setDefaultRolePrefix("");
handler.setPermissionEvaluator(permissionEvaluator);
return handler;
}
#Override
protected MethodSecurityExpressionHandler createExpressionHandler() {
return expressionHandler();
}
}
SecurityConfig:
#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Bean(name = "clientAuthenticationEntryPoint")
public OAuth2AuthenticationEntryPoint oauthAuthenticationEntryPoint() {
OAuth2AuthenticationEntryPoint entry = new OAuth2AuthenticationEntryPoint();
entry.setRealmName("myapp/client");
entry.setTypeName("Basic");
return entry;
}
#Autowired
#Qualifier("webExpressionHandler")
private DefaultWebSecurityExpressionHandler expressionHandler;
#Bean
#Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
#Bean
public SessionRegistry sessionRegistry() {
return new SessionRegistryImpl();
}
#Override
public void configure(WebSecurity web) throws Exception {
web.ignoring()
.antMatchers("/html/**", "/webapi/**");
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.requestMatchers().antMatchers("/admin/**", "/**")
.and()
.authorizeRequests()
.expressionHandler(expressionHandler)
.antMatchers("/admin/**").access("hasRole('ADMINISTRATOR')")
.antMatchers("/1/admin/**").access("hasRole('ADMINISTRATOR')")
.antMatchers("/profile**").authenticated()
.antMatchers("/oauth/authorize").authenticated()
.and()
.formLogin().loginPage("/login")
.failureUrl("/login?error=1")
.loginProcessingUrl("/login-attempt")
.defaultSuccessUrl("/", false)
.and()
.sessionManagement()
.sessionFixation().migrateSession()
.and()
.logout()
.logoutUrl("/logout")
.logoutSuccessUrl("/")
.and()
.exceptionHandling()
.accessDeniedPage("/access-denied")
.and()
.csrf();
}
}
Oauth config:
#Configuration
public class Oauth {
#Configuration
#EnableResourceServer
public static class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {
private static final String RESOURCE_ID = "my_oauth_server";
#Override
public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
resources.resourceId(RESOURCE_ID);
}
#Override
public void configure(HttpSecurity http) throws Exception {
http
.anonymous().disable()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
.regexMatchers("/api/v0/.*").authenticated()
.antMatchers("/**").denyAll()
;
}
}
#Configuration
#EnableAuthorizationServer
protected static class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter {
#Autowired
private AuthenticationManager authenticationManager;
#Autowired
private AuthorizationCodeServices verificationCodeService;
#Autowired
#Qualifier("clientDetails")
private ClientDetailsService clientDetailsService;
#Autowired
#Qualifier("tokenStore")
private TokenStore tokenStore;
#Bean(name = "tokenServices")
public DefaultTokenServices tokenServices() {
DefaultTokenServices tokenServices = new DefaultTokenServices();
tokenServices.setTokenStore(tokenStore);
tokenServices.setSupportRefreshToken(true);
tokenServices.setClientDetailsService(clientDetailsService);
return tokenServices;
}
#Bean
public ClientCredentialsTokenEndpointFilter clientCredentialsTokenEndpointFilter() throws Exception {
ClientCredentialsTokenEndpointFilter filter = new ClientCredentialsTokenEndpointFilter();
filter.setAuthenticationManager(authenticationManager);
return filter;
}
#Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.withClientDetails(clientDetailsService);
}
#Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.authenticationManager(authenticationManager);
endpoints.authorizationCodeServices(verificationCodeService);
endpoints.tokenServices(tokenServices());
endpoints.reuseRefreshTokens(true);
}
#Override
public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
oauthServer.tokenKeyAccess("permitAll()");
oauthServer.checkTokenAccess("permitAll()");
oauthServer.realm("myapp/client");
oauthServer.addTokenEndpointAuthenticationFilter(clientCredentialsTokenEndpointFilter());
oauthServer.allowFormAuthenticationForClients();
}
}
}
So, ResourceServer config overlap other configuration. How can I fix it? I would be thankful for any help.

I see that you want to protect some endpoints with an access token, and other endpoints with normal form login.
Can you try restricting the applicability of your ResourceServerConfiguration to apply only to certain endpoints by something like: http.requestMatcher(new AntPathRequestMatcher("/api/v0/**")).... Do the same for SecurityConfig but for the endpoints you want it to take care of.

Related

Spring Security without the WebSecurityConfigurerAdapter

I am trying to update to Spring Boot 2.7.0-SNAPSHOT.
WebSecurityConfigurerAdapter is deprecated in this version.
Old WebSecurityConfig with WebSecurityConfigurerAdapter (working fine):
/**
* SecurityConfig
*
*/
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private CustomAuthenticationSuccessHandler customAuthenticationSuccessHandler;
#Autowired
private CustomAuthenticationFailureHandler customAuthenticationFailureHandler;
#Autowired
private OAuth2AuthenticationSuccessHandler oAuth2AuthenticationSuccessHandler;
#Autowired
private OAuth2AuthenticationFailureHandler oAuth2AuthenticationFailureHandler;
#Autowired
private OAuth2UserServiceImpl oAuth2UserServiceImpl;
/**
* for development
*
* #return
*/
#Bean
public PasswordEncoder passwordEncoder() {
// for development
return NoOpPasswordEncoder.getInstance();
}
#Override
public void configure(WebSecurity web) {
// ignoring
web.ignoring().antMatchers("/css/**", "/js/**", "/img/**", "/lib/**", "/favicon.ico", "/oauth2");
}
#Override
public void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().antMatchers("/", "/login", "/error", "/message/**").permitAll();
http.authorizeRequests().anyRequest().authenticated();
http.formLogin();
http.exceptionHandling().authenticationEntryPoint(authenticationEntryPoint("/login"));
http.addFilterBefore(authenticationFilter(), UsernamePasswordAuthenticationFilter.class);
// OAuth2
http.oauth2Login().loginPage("/").defaultSuccessUrl("/home", false);
http.oauth2Login().userInfoEndpoint().userService(oAuth2UserServiceImpl);
http.oauth2Login().successHandler(oAuth2AuthenticationSuccessHandler);
http.oauth2Login().failureHandler(oAuth2AuthenticationFailureHandler);
http.logout().logoutUrl("/logout").logoutSuccessUrl("/login").deleteCookies("JSESSIONID");
http.csrf().disable();
http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED)
.enableSessionUrlRewriting(false);
}
private MyAuthenticationFilter authenticationFilter() throws Exception {
MyAuthenticationFilter filter = new MyAuthenticationFilter();
filter.setAuthenticationManager(authenticationManagerBean());
filter.setAuthenticationSuccessHandler(customAuthenticationSuccessHandler);
filter.setAuthenticationFailureHandler(customAuthenticationFailureHandler);
filter.setRequiresAuthenticationRequestMatcher(new AntPathRequestMatcher("/authentication", "POST"));
return filter;
}
private AuthenticationEntryPoint authenticationEntryPoint(String loginFormUrl) {
return new MyLoginUrlAuthenticationEntryPoint(loginFormUrl);
}
}
After reading this blog post, I have modified the new WebSecurityConfig:
/**
* SecurityConfig
*
*/
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig {
#Autowired
private CustomAuthenticationSuccessHandler customAuthenticationSuccessHandler;
#Autowired
private CustomAuthenticationFailureHandler customAuthenticationFailureHandler;
#Autowired
private OAuth2AuthenticationSuccessHandler oAuth2AuthenticationSuccessHandler;
#Autowired
private OAuth2AuthenticationFailureHandler oAuth2AuthenticationFailureHandler;
#Autowired
private OAuth2UserServiceImpl oAuth2UserServiceImpl;
/**
* for development
*
* #return
*/
#Bean
public PasswordEncoder passwordEncoder() {
// for development
return NoOpPasswordEncoder.getInstance();
}
#Bean
public WebSecurityCustomizer webSecurityCustomizer() {
return (web) -> web.ignoring().antMatchers(
"/css/**", "/js/**", "/img/**", "/lib/**", "/favicon.ico", "/oauth2");
}
#Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.authorizeRequests().antMatchers("/", "/login", "/error", "/message/**").permitAll();
http.authorizeRequests().anyRequest().authenticated();
http.formLogin();
http.exceptionHandling().authenticationEntryPoint(authenticationEntryPoint("/login"));
http.addFilterBefore(authenticationFilter(), UsernamePasswordAuthenticationFilter.class);
// OAuth2
http.oauth2Login().loginPage("/").defaultSuccessUrl("/home", false);
http.oauth2Login().userInfoEndpoint().userService(oAuth2UserServiceImpl);
http.oauth2Login().successHandler(oAuth2AuthenticationSuccessHandler);
http.oauth2Login().failureHandler(oAuth2AuthenticationFailureHandler);
http.logout().logoutUrl("/logout").logoutSuccessUrl("/login").deleteCookies("JSESSIONID");
http.csrf().disable();
http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED)
.enableSessionUrlRewriting(false);
return http.build();
}
private MyAuthenticationFilter authenticationFilter() throws Exception {
MyAuthenticationFilter filter = new MyAuthenticationFilter();
// How can I fix this? ------------------------------------------
filter.setAuthenticationManager(authenticationManagerBean());
// --------------------------------------------------------------
filter.setAuthenticationSuccessHandler(customAuthenticationSuccessHandler);
filter.setAuthenticationFailureHandler(customAuthenticationFailureHandler);
filter.setRequiresAuthenticationRequestMatcher(new AntPathRequestMatcher("/authentication", "POST"));
return filter;
}
private AuthenticationEntryPoint authenticationEntryPoint(String loginFormUrl) {
return new MyLoginUrlAuthenticationEntryPoint(loginFormUrl);
}
}
I was able to fix two methods.
(#configure(WebSecurity web) and #configure(HttpSecurity http))
However, I can't figure out how to fix authenticationManagerBean().
Where do I get the AuthenticationManager from?
Here's the entire class that took me day to configure. Hope it could save your time.
#Configuration
#EnableWebSecurity
#RequiredArgsConstructor
public class ApplicationSecurityConfig {
private final UserDetailsService userService;
private final AuthenticationConfiguration configuration;
#Bean
SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
AbstractAuthenticationProcessingFilter filter = new CustomizedAuthenticationFilter(authenticationManager());
filter.setFilterProcessesUrl("/api/login");
http.csrf().disable();
http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
http.authorizeRequests().antMatchers(HttpMethod.POST, "/api/login").permitAll();
http.authorizeRequests().anyRequest().authenticated();
http.addFilter(filter);
return http.build();
}
#Bean
AuthenticationManager authenticationManager() throws Exception {
return configuration.getAuthenticationManager();
}
#Autowired
void configure(AuthenticationManagerBuilder builder) throws Exception {
builder.userDetailsService(userService).passwordEncoder(new BCryptPasswordEncoder());
}
}
You can create a custom DSL. This is actually how Spring Security works internally.
public class MyCustomDsl extends AbstractHttpConfigurer<MyCustomDsl, HttpSecurity> {
#Override
public void configure(HttpSecurity http) throws Exception {
AuthenticationManager authenticationManager = http.getSharedObject(AuthenticationManager.class);
http.addFilterBefore(new MyAuthenticationFilter(authenticationManager), UsernamePasswordAuthenticationFilter.class);
}
public static MyCustomDsl customDsl() {
return new MyCustomDsl();
}
}
Then you can apply the custom DSL when building the SecurityFilterChain:
#Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
// ...
http.apply(customDsl());
return http.build();
}
If you want to inject AuthenticationManager into other spring components, you can use the following configuration.
#Bean
public AuthenticationManager authenticationManager(AuthenticationConfiguration authenticationConfiguration) throws Exception {
return authenticationConfiguration.getAuthenticationManager();
}
This approach has solved the problem for me and you can inject AuthenticationManager wherever you need.
EDIT:
#EnableWebSecurity
#RequiredArgsConstructor
public class SpringSecurityConfiguration {
private final AuthenticationConfiguration authenticationConfiguration;
#Bean
public AuthenticationManager authenticationManager() throws Exception
{
return authenticationConfiguration.getAuthenticationManager();
}

Periodically the retrieved user from the spring security context is empty

I have spring web mvc project with Spring Security 4.1.0.RELEASE
In spring controller i try fetch the user from the context
#RestController
public class Test {
#RequestMapping(value="test", method = RequestMethod.POST)
public ResponseEntity<Void> test() {
ContextUser user = (ContextUser) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
}
}
user is an instance with id = 0, login = null .... It is empty instance.
org.springframework.security.core.Authentication isAuthenticated = true, list of Collection<? extends GrantedAuthority> are correct This behaviour is occurred periodically. It is not every time for this request. I catch this issue only for that request
My configurations
#Configuration
#ComponentScan(basePackages={"com.test.app"},
excludeFilters=#ComponentScan.Filter(type=FilterType.REGEX, pattern={"com.test.app.web.*"}))
#PropertySource(value = { "classpath:application.properties" })
#EnableAspectJAutoProxy
public class AppConfig {
#Autowired
private DataSource dataSource;
//My beans
}
#Component
public class TestUserDetailsService implements UserDetailsService{
#Autowired
private TestUserService service;
#Override
public UserDetails loadUserByUsername(String userName)
throws UsernameNotFoundException {
User user = service.findByLogin(userName);
if (user == null) {
throw new UsernameNotFoundException("Error");
}
return new ContextUser(user);
}
}
public class ContextUser extends User implements UserDetails {
//...
}
#Configuration
#EnableWebSecurity
#EnableAsync
#EnableGlobalMethodSecurity(securedEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter
{
#Autowired
private TestAuthenticationEntryPoint testAuthenticationEntryPoint;
#Autowired
private TestSimpleUrlAuthenticationSuccessHandler testSimpleUrlAuthenticationSuccessHandler;
#Autowired
private TestSimpleUrlAuthenticationFailureHandler testSimpleUrlAuthenticationFailureHandler;
#Autowired
private LogoutSuccessHandler logoutSuccessHandler;
#Autowired
private TestUserDetailsService testUserDetailsService;
#Bean
#Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
#Override
protected void configure(AuthenticationManagerBuilder registry) throws MyException {
registry.userDetailsService(testUserDetailsService).passwordEncoder(new TestEncoder());
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.addFilterBefore(new CorsFilter(), ChannelProcessingFilter.class);
http.csrf()
.disable()
.exceptionHandling()
.authenticationEntryPoint(testAuthenticationEntryPoint)
.and().sessionManagement().sessionFixation().migrateSession().maximumSessions(-1).sessionRegistry(sessionRegistry()).and()
.and()
.authorizeRequests()
.antMatchers("/").access("hasAuthority('TEST')")
.anyRequest().authenticated()
.and()
.formLogin()
.successHandler(testSimpleUrlAuthenticationSuccessHandler)
.failureHandler(testSimpleUrlAuthenticationFailureHandler)
.and()
.logout().logoutSuccessHandler(logoutSuccessHandler)
.and()
.headers().cacheControl().disable().frameOptions().sameOrigin();
}
#Bean
public SessionRegistry sessionRegistry() {
return new SessionRegistryImpl();
}
#Override
public void configure(WebSecurity web) {
web.ignoring().antMatchers("/resources/**");
}
}
Are any ideas why this behaviour is happened?

Spring security authentication server

I am working on authentication service part of cloud app and I created the following security config class.
#Configuration
#EnableWebSecurity
public class JwtSecurityConfig extends WebSecurityConfigurerAdapter {
private final PasswordEncoder encoder;
private final UserService userService;
private final JwtConstant jwtConstant;
#Autowired
public JwtSecurityConfig(PasswordEncoder encoder, UserService userService, JwtConstant jwtConstant) {
this.encoder= encoder;
this.userService = userService;
this.jwtConstant = jwtConstant;
}
#Bean
public DaoAuthenticationProvider getAuthenticationProvider() {
DaoAuthenticationProvider authenticationProvider = new DaoAuthenticationProvider();
authenticationProvider.setPasswordEncoder(encoder);
authenticationProvider.setUserDetailsService(userService);
return authenticationProvider;
}
#Override
protected void configure(AuthenticationManagerBuilder auth) {
auth.authenticationProvider(getAuthenticationProvider());
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.addFilter(getAuthenticationFilter())
.authorizeRequests()
.antMatchers(HttpMethod.PUT, "/signup").permitAll()
.anyRequest()
.authenticated();
}
private AuthenticationFilter getAuthenticationFilter() throws Exception {
return new AuthenticationFilter(authenticationManager(), jwtConstant);
}
}
I am not sure about the chain methods of configure(HttpSecurity http) method. The authentication service will only receive "login" and "signup" requests.
Should I remove authorizeRequests() method as I do not authorize anything?
I am not sure about anyRequest().authenticated() part either if I really need it?
there are a couple of things that have to be changed, but first of all, you have to define a method that will provide jwt for each request and every request should provide an AuthRequest object that contains username and password :
#RestController
public class WelcomeController {
#Autowired
private JwtUtil jwtUtil;
#Autowired
private AuthenticationManager authenticationManager;
#PostMapping("/signup")
public String generateToken(#RequestBody AuthRequest authRequest) throws Exception {
try {
authenticationManager.authenticate(
new UsernamePasswordAuthenticationToken(authRequest.getUserName(), authRequest.getPassword())
);
} catch (Exception ex) {
throw new Exception("inavalid username/password");
}
return jwtUtil.generateToken(authRequest.getUserName());
}
}
and in the UserDetailsService you can make authentication as below :
#Service
public class UserDetailsService implements org.springframework.security.core.userdetails.UserDetailsService {
#Autowired
private final UserRepository userRepository;
#Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
System.out.println("tried to loging : " + username);
if(!Objects.isNull(username) && !"".equals(username)){
Optional<User> user = userRepository.findUserByUserName(username);
System.out.println(user.get());
if(user.isPresent()){
User userParam = user.get();
return new org.springframework.security.core.userdetails.User(userParam.getUserName(),
userParam.getPassword(), new ArrayList<>());
}
}
throw new UsernameNotFoundException("user does not exists or empty !!");
}
}
and for the configuration side :
#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private final UserDetailsService userDetailsService;
#Autowired
private final JwtFilter jwtFilter;
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
}
#Bean
public PasswordEncoder passwordEncoder(){
return new BCryptPasswordEncoder(10);
}
#Bean(name = BeanIds.AUTHENTICATION_MANAGER)
#Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.authorizeRequests().antMatchers("/signup").permitAll()
.anyRequest().authenticated()
.and().exceptionHandling().and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS);
http.addFilterBefore(jwtFilter, UsernamePasswordAuthenticationFilter.class);;
}
}
for further information, you can follow my Github branch Authnticaition sample

Spring Oauth2 redirect uri doesn't change

I'm working on OAuth2 Authorization in Spring and try to implement authorization code grant flow. Now I have two applications. Client side and authorization server side. When I open secured /client/hello it redirect me to oauth2 login page, after that a get /oauth/authorize link, but in redirect_uri value always is login page on client side and it even doesn't change manually in browser. How I can change it? If i change redirect uri to /client/login in auth server config it redirects and gives me authorization code, but invokes unauthorized error.
Client
Controller:
#RestController
public class Controller {
#GetMapping("/hello")
public String hello() {
return "Hello world!!";
}
#GetMapping("/public")
public String publicPage() {
return "This is public!!";
}
#GetMapping("/callback")
public String login(#RequestParam("code") String code) {
return code;
}
}
Client security config:
#Configuration
#EnableOAuth2Sso
public class ClientSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/error**", "/public**").permitAll()
.anyRequest().authenticated();
}
}
Client properties:
security.oauth2.client.client-id=007314
security.oauth2.client.client-secret=MDA3MzE0
security.oauth2.client.grant-type=password
security.oauth2.client.scope=read
security.oauth2.client.pre-established-redirect-uri=http://localhost:8081/client/public
security.oauth2.client.access-token-uri=http://localhost:8082/auth/oauth/token
security.oauth2.client.user-authorization-uri=http://localhost:8082/auth/oauth/authorize
security.oauth2.client.authentication-scheme=form
security.oauth2.resource.user-info-uri=http://localhost:8081/client/hello
security.oauth2.resource.id=resource-server-rest-api
server.port=8081
server.servlet.context-path=/client
Authorization Server
Server config:
#Configuration
#EnableAuthorizationServer
public class AuthorizationServer extends AuthorizationServerConfigurerAdapter {
private final PasswordEncoder passwordEncoder;
#Qualifier("authenticationManagerBean")
private final AuthenticationManager authenticationManager;
#Autowired
public AuthorizationServer(PasswordEncoder passwordEncoder, AuthenticationManager authenticationManager) {
this.passwordEncoder = passwordEncoder;
this.authenticationManager = authenticationManager;
}
#Override
public void configure(AuthorizationServerSecurityConfigurer security) {
security.tokenKeyAccess("permitAll()")
.checkTokenAccess("isAuthenticated()")
.passwordEncoder(passwordEncoder)
.allowFormAuthenticationForClients();
}
#Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
.withClient("007314")
.secret(passwordEncoder.encode("007314"))
.authorizedGrantTypes("authorization_code", "refresh_token")
.scopes("read")
.resourceIds("resource-server-rest-api")
.autoApprove(true)
.redirectUris("http://localhost:8081/client/hello");
}
#Bean
public TokenStore tokenStore(){
return new JwtTokenStore(defaultAccessTokenConverter());
}
#Bean
public JwtAccessTokenConverter defaultAccessTokenConverter() {
JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
converter.setSigningKey("123");
return converter;
}
#Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) {
endpoints.tokenStore(tokenStore())
.accessTokenConverter(defaultAccessTokenConverter())
.authenticationManager(authenticationManager);
}
}
Server security config:
#EnableWebSecurity
#Order(1)
public class ServerSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
#Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
#Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication().passwordEncoder(passwordEncoder())
.withUser("qwerty")
.password(passwordEncoder().encode("12345"))
.roles("USER");
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/error**", "/login**", "/oauth/authorize**").permitAll()
.anyRequest().authenticated()
.and()
.formLogin().permitAll();
}
}
Resource Server
#Configuration
#EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
private static final String RESOURCE_ID = "resource-server-rest-api";
#Override
public void configure(ResourceServerSecurityConfigurer resources) {
resources.resourceId(RESOURCE_ID);
}
#Override
public void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers(HttpMethod.GET, "/client/hello").access("#oauth2.hasScope('read')");
}
}
Server properties:
server.port=8082
server.servlet.context-path=/auth
Add also: security.oauth2.client.useCurrentUri=false into client.properties.

Springfox Spring Boot UI not accessible: Unabled to Infer Base URL

I am using Spring Boot: v2.0.3.RELEASE and Spring Fox: v2.9.2.
Trying to access http://127.0.0.1:8080/swagger-ui.html results in:
Unable to infer base url. This is common when using dynamic servlet
registration or when the API is behind an API Gateway. The base url is
the root of where all the swagger resources are served. For e.g. if
the api is available at http://example.org/api/v2/api-docs then the
base url is http://example.org/api/. Please enter the location
manually:
Repeatedly clicking OK in the popup bar has no effect.
Here is my Spring Security Configuration:
#Configuration
#EnableWebSecurity
public class WebSecurityConfig {
private UserDetailsService userDetailsService;
private BCryptPasswordEncoder bCryptPasswordEncoder;
private SecurityProperties securityProperties;
private AppProperties AppProperties;
public WebSecurityConfig(UserDetailsService userDetailsService,
BCryptPasswordEncoder bCryptPasswordEncoder,
SecurityProperties securityProperties,
AppProperties AppProperties) {
this.userDetailsService = userDetailsService;
this.bCryptPasswordEncoder = bCryptPasswordEncoder;
this.securityProperties = securityProperties;
this.AppProperties = AppProperties;
}
#Configuration
#Order(1)
public class BasicAuthenticationConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.antMatcher("/admin/**")
.csrf().disable()
.httpBasic().and()
.authorizeRequests().anyRequest().hasRole("ADMIN").and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
}
#Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser(AppProperties.getAdminUsername())
.password(bCryptPasswordEncoder.encode(AppProperties.getAdminPassword()))
.roles("ADMIN");
}
}
#Configuration
#Order(2)
public class TokenAuthenticationConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.
cors().and().csrf().disable()
.authorizeRequests()
.antMatchers("/no-auth/**").permitAll()
.anyRequest().authenticated()
.and()
.addFilter(new JWTAuthenticationFilter(securityProperties, authenticationManager()))
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
}
#Override
public void configure(WebSecurity web) throws Exception {
web.ignoring()
.antMatchers("/v2/api-docs", "**/swagger-resources/**", "/swagger-ui.html", "/webjars/**")
.antMatchers(HttpMethod.OPTIONS, "/**");
}
#Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(bCryptPasswordEncoder);
}
#Bean
CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration corsConfiguration = new CorsConfiguration();
corsConfiguration.applyPermitDefaultValues();
corsConfiguration.setAllowedOrigins(Collections.singletonList("*"));
corsConfiguration.setAllowedMethods(Arrays.asList("GET", "POST", "DELETE"));
corsConfiguration.setMaxAge(3600L);
final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", corsConfiguration);
return source;
}
}
}
Here is the SpringFox configuration:
#Configuration
#EnableSwagger2
public class SwaggerConfig {
#Autowired
private AppProperties AppProperties;
#Bean
public WebMvcConfigurer mvcConfigurer() {
return new WebMvcConfigurer() {
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("swagger-ui.html")
.addResourceLocations("classpath:/META-INF/resources/");
registry.addResourceHandler("/webjars/**")
.addResourceLocations("classpath:/META-INF/resources/webjars/");
}
};
}
#Bean
public Docket api() {
return new Docket(DocumentationType.SWAGGER_2)
.groupName("foo-api")
.apiInfo(apiInfo())
.useDefaultResponseMessages(false)
.produces(Collections.singleton("application/json"))
.select()
.apis(RequestHandlerSelectors.any())
.paths(PathSelectors.any())
.build();
}
private ApiInfo apiInfo() {
return new ApiInfoBuilder()
.title("Foo API")
.termsOfServiceUrl(AppProperties.getApiTosUrl())
.version("1.0").build();
}
}
In my Spring-Security Configuration, I have tried to exclude all Spring-Fox paths as generally advised but it doesn't have any effect. What is going wrong?

Categories

Resources