Spring boot authentication - admin console 403 response to client - java

I'm using jdk 1.8 and Spring boot 2.1.2.
I would like to enable authentication in administration console of Spring Boot and in its clients.
I setted in Administration application.properties:
spring.security.user.name=admin
spring.security.user.password=secret
spring.boot.admin.discovery.enabled=true
management.endpoints.web.exposure.include=*
management.endpoints.web.cors.allowed-methods=GET,POST
In Administration project I added this class:
#EnableWebSecurity
#Configuration
public class SecuritySecureConfig extends WebSecurityConfigurerAdapter {
private static final Logger logger = (Logger) LoggerFactory.getLogger(SecuritySecureConfig.class);
private final String adminContextPath;
public SecuritySecureConfig(AdminServerProperties adminServerProperties) {
this.adminContextPath = adminServerProperties.getContextPath();
}
#Override
protected void configure(HttpSecurity http) throws Exception {
SavedRequestAwareAuthenticationSuccessHandler successHandler = new SavedRequestAwareAuthenticationSuccessHandler();
successHandler.setTargetUrlParameter("redirectTo");
successHandler.setDefaultTargetUrl(adminContextPath + "/");
http.authorizeRequests()
.antMatchers(adminContextPath + "/assets/**").permitAll()
.antMatchers(adminContextPath + "/login").permitAll()
.anyRequest().authenticated()
.and()
.formLogin().loginPage(adminContextPath + "/login").successHandler(successHandler).and()
.logout().logoutUrl(adminContextPath + "/logout").and()
.httpBasic().and()
.csrf()
.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
.ignoringAntMatchers(
adminContextPath + "/instances",
adminContextPath + "/actuator/**"
);
}
}
In administration pom.xml I added:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>de.codecentric</groupId>
<artifactId>spring-boot-admin-starter-server</artifactId>
</dependency>
<dependency>
<groupId>de.codecentric</groupId>
<artifactId>spring-boot-admin-server-ui</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</dependency>
</dependencies>
I was forced to add the annotation #EnableWebFluxSecurity on the main class because without it, it gives an Exception:
org.springframework.beans.factory.support.BeanDefinitionOverrideException:
Invalid bean definition with name 'springSecurityFilterChain' defined
in class path resource
[org/springframework/boot/actuate/autoconfigure/security/reactive/ReactiveManagementWebSecurityAutoConfiguration.class]:
Cannot register bean definition [Root bean: class [null]; scope=;
abstract=false; lazyInit=false; autowireMode=3; dependencyCheck=0;
autowireCandidate=true; primary=false;
factoryBeanName=org.springframework.boot.actuate.autoconfigure.security.reactive.ReactiveManagementWebSecurityAutoConfiguration;
factoryMethodName=springSecurityFilterChain; initMethodName=null;
destroyMethodName=(inferred); defined in class path resource
[org/springframework/boot/actuate/autoconfigure/security/reactive/ReactiveManagementWebSecurityAutoConfiguration.class]]
for bean 'springSecurityFilterChain': There is already [Root bean:
class [null]; scope=; abstract=false; lazyInit=false; autowireMode=3;
dependencyCheck=0; autowireCandidate=true; primary=false;
factoryBeanName=org.springframework.security.config.annotation.web.configuration.WebSecurityConfiguration;
factoryMethodName=springSecurityFilterChain; initMethodName=null;
destroyMethodName=(inferred); defined in class path resource
[org/springframework/security/config/annotation/web/configuration/WebSecurityConfiguration.class]]
bound.
In client application.properties:
spring.security.user.name=joe
spring.security.user.password=my-secret-password
spring.boot.admin.client.username=admin
spring.boot.admin.client.password=secret
spring.boot.admin.client.instance.metadata.user.name=admin
spring.boot.admin.client.instance.metadata.user.password=secret
spring.boot.admin.client.enabled=true
spring.boot.admin.client.auto-registration=true
spring.boot.admin.client.auto-deregistration=true
And in client pom.xml:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
Now if I access both of them using the browser, they prompt me with the login form. I type the login and password and all works as a charm, but the actuator of the client cannot access to the admin, it returns always 403 FORBIDDEN.
2019-02-12 15:21:52.004 - [registrationTask1] DEBUG
o.s.core.log.CompositeLog.debug 142 - Response 403 FORBIDDEN
I really cannot understand why the communication between the administration console and the client does not work.
Does anyone know where I'm wrong?

I have the same problem
so, use
#EnableWebFluxSecurity
and not
#EnableWebSecurity
like this
#Configuration
#EnableWebFluxSecurity
public class AppSecurityConfig {
private final AdminServerProperties adminServer;
public AppSecurityConfig (AdminServerProperties adminServer) {
this.adminServer = adminServer;
}
#Bean
public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
http
.securityMatcher(new NegatedServerWebExchangeMatcher(
ServerWebExchangeMatchers.pathMatchers("/instances")))
.securityMatcher(new NegatedServerWebExchangeMatcher(
ServerWebExchangeMatchers.pathMatchers("/actuator/**")))
.authorizeExchange()
.anyExchange().authenticated()
.and()
.formLogin()
.loginPage(this.adminServer.getContextPath() + "/login")
.and()
.logout()
.logoutUrl(this.adminServer.getContextPath() + "/logout")
.and()
.httpBasic()
.and()
.csrf().disable();
return http.build();
} }
in you application.yml
spring:
security:
user:
password: ${ADMIN_PASSWORD}
name: ${ADMIN_USER}
application:
name: Admin Server
boot:
admin:
client:
username: ${ADMIN_USER}
password: ${ADMIN_PASSWORD}
url: ${ADMIN_SERVER_URL}
enabled: true
ui:
cache:
no-cache: true
title: App Monitoring
instance:
name: ${spring.application.name}
main:
allow-bean-definition-overriding: true
management:
endpoints:
web:
exposure:
include: "*"
cors:
allowed-origins: "*"
allowed-methods: GET,POST
endpoint:
health:
show-details: always
It can monitor it self if you want
in the client side app
spring:
boot:
admin:
client:
url: ${ADMIN_SERVER_URL}
username: ${ADMIN_USER}
password: ${ADMIN_PASSWORD}
instance:
name: ${spring.application.name}
auto-registration: true
application:
name: Client App

Related

springdoc-openapi-ui returning 406 error-not-acceptable

I am using springdoc-openapi-ui for my web application but when I hit http://localhost:8080/swagger-ui/index.html in the browser I am getting 406 error code.
Below is the dependency in pom.xml
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-ui</artifactId>
<version>1.6.14</version>
</dependency>
And Spring Security config is
#Configuration
#EnableWebSecurity
public class SpringSecurityConfig {
#Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.authorizeRequests().antMatchers("/").permitAll();
http.headers().frameOptions().sameOrigin();
return http.build();
}
#Bean
public WebSecurityCustomizer webSecurityCustomizer() {
return web -> web.ignoring().antMatchers("/swagger-ui/**", "/v3/api-docs/**");
}
Spring boot version I am using 2.7.7
Below is network detail via inspect element in chrome for the swagger-ui.config ..

Granted Authority List is Empty after Migration to Spring Security 6

After the migration to spring boot 3 and spring security 6, I have issues to authorize my anonymous authentification properly. Iam using an oath2 resource server and azure active directory. The granted authority list is always empty. do i have to tweak my web security configuration somehow?
snippet from WebSecurityConfig class after migration:
#Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
log.debug("Configuring HTTP Security");
http
.csrf().disable()
.cors()
.and()
.headers()
.frameOptions().disable()
.and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.exceptionHandling()
.and()
.authorizeRequests((authorize) ->
authorize.requestMatchers(HttpMethod.GET, "/sf/**", "/assets/**", "/resources/**", "/built/**", "/ui/**").permitAll()
.and()
.addFilterBefore(new RolesToRightsConverterFilter(s3RSpringConfig), BasicAuthenticationFilter.class)
.addFilterAfter(new Slf4jMDCFilter(authService, tracingService), RolesToRightsConverterFilter.class))
.oauth2ResourceServer().jwt().jwtAuthenticationConverter(new JwtBearerTokenAuthenticationConverter());
return http.build();
}
and the relevant part of application.yml:
security:
oauth2:
resourceserver:
jwt:
issuer-uri: 'https://login.microsoftonline.com/${add_tenant_id}/v2.0'
audiences: '${add_client_id:xxx}'
cloud:
azure:
active-directory:
credential:
client-id: ${add_client_id:xxx}
client-secret: xxx
profile:
tenant-id: ${add_tenant_id:xxx}
jwk-set-cache-lifespan: 10m
jwk-set-cache-refresh-time: 10m
enabled: true
the xxx is just a placeholder for the actual ID.

Keycloak redirects too many times after login in Spring gateway cloud

I am building one spring cloud gateway and in that I am implementing Keycloak Security everything works fine but once login done on keycloak it is not redirecting back and showing error too many redirects I am not sure what I am missing?
Below are the dependencies which I am using:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
And my application Api gateway start application code is as below:
#SpringBootApplication
#ComponentScan(basePackages = {"com", "com.b","com.auth","com.security"})
public class APIGatewayApplication {
public static void main(String[] args) {
SpringApplication.run(APIGatewayApplication.class, args);
}
#Bean
public KeycloakConfigResolver keycloakConfigResolver() {
return new PathBasedKeycloakConfigResolver();
}
}
Security Config http code is as below:
#Configuration
public class SecurityConfig {
#Bean
public SecurityWebFilterChain springSecurityFilterChain (ServerHttpSecurity http) {
http
.authorizeExchange()
.anyExchange()
.authenticated()
.and()
.oauth2Login(); // to redirect to oauth2 login page.
return http.build();
}
}
and in my application.yml file I am adding below configuration:
spring:
security:
oauth2:
client:
provider:
my-keycloak-provider:
issuer-uri: http://localhost:8280/auth/realms/Default
registration:
keycloak-spring-gateway-client:
provider: my-keycloak-provider
client-id: Default
client-secret: 8ZRUH62Pfhfde6uqasD8dfgdhvqWt03K6
authorization-grant-type: authorization_code
redirect-uri: '{baseUrl}/app'
main:
web-application-type: reactive
application:
name: app
cloud:
gateway:
default-filters:
- TokenRelay
So when I start application it is running fine and it is getting redirected to the Keycloak login page and after login it shows error "localhost redirected you too many times." How to resolve it so once it is login it should redirected once only to main application? Please help.

Why does my OAuth2 won't working with Spring Boot?

I'm trying to setup Facebook login with OAuth2 for Spring Boot.
First I have my spring security configuration. I want every page from www.localhost:8080/Intranet/** to become blocked for people that haven't been authorized by Facebook.
#Configuration
#EnableOAuth2Client
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.antMatcher("/Intranet/**")
.authorizeRequests()
.antMatchers("/", "/Intranet")
.permitAll()
.anyRequest()
.authenticated()
.and()
.logout().logoutSuccessUrl("/").permitAll();
}
}
I create my application.yml here:
spring:
application:
name: spektrakonhemsida
security:
oauth2:
client:
registration:
facebook:
clientId: myID
clientSecret: mySecret
accessTokenUri: https://graph.facebook.com/oauth/access_token
userAuthorizationUri: https://www.facebook.com/dialog/oauth
tokenName: oauth_token
authenticationScheme: query
clientAuthenticationScheme: form
resource:
userInfoUri: https://graph.facebook.com/me
# Server configuration
server:
port: 8080
error:
whitelabel:
enabled: false
Then I have my dependencies for Spring Security and OAuth2:
<dependency>
<groupId>org.springframework.security.oauth.boot</groupId>
<artifactId>spring-security-oauth2-autoconfigure</artifactId>
<version>2.2.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-oauth2-client</artifactId>
</dependency>
<!-- Prevent /error to crash -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
This is what's happening:
When I access www.localhost:8080/Intranet <- Works perfekt!
When I access www.localhost:8080/Intranet/Bokning <- I will be navigated to /error where my text shows up "You have no rights here! Please login".
But I want users to become automatically navigated to Facebook's login page when they enters /Intranet/**
Why does this not happening?
Found a solution now. This need to be done to make it work with Facebook.
Security:
#Configuration
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
#Override
public void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.authorizeRequests()
.antMatchers("/Intranet/Bokning").authenticated() // Block this
.antMatchers("/**", "/Intranet**").permitAll() // Allow this for all
.anyRequest().authenticated()
.and().logout().logoutSuccessUrl("/").permitAll()
.and()
.oauth2Login();
}
}
And appllication.yml
spring:
security:
oauth2:
client:
registration:
facebook:
clientId: myID
clientSecret: mySecret
accessTokenUri: https://graph.facebook.com/oauth/access_token
userAuthorizationUri: https://www.facebook.com/dialog/oauth
tokenName: oauth_token
authenticationScheme: query
clientAuthenticationScheme: form
resource:
userInfoUri: https://graph.facebook.com/me
server:
port: 8080
And pom.xml file:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-oauth2-client</artifactId>
</dependency>

Spring OAuth 2 authorization server authenticates clients using user details service

I have a Spring boot application with spring-security-oauth2-autoconfigure. The resource server and authorization server run in the same application.
The application has an user details service globally configure throught WebSecurityConfiguration. It is used to resources' owner authentication.
I have configured the authorization server to authenticate the clients using a in memory store, like that:
#Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
.withClient("devglan-client")
.secret("$2a$04$e/c1/RfsWuThaWFCrcCuJeoyvwCV0URN/6Pn9ZFlrtIWaU/vj/BfG")
.authorizedGrantTypes("implicit","refresh_token", "password", "authorization_code")
.scopes("read write trust");
}
The problem:
When I try to get an authorization code using the GET authorize endpoint, then the Spring Security tries to authenticate the application client using the user details service.
I include in the request a HTTP Authorization Header with the Basic option which contains the cliend_id:client_secret credentials.
GET /oauth/authorize?
response_type=code&client_id=bpclient&scope=read HTTP/1.1
Host: localhost:8080
Accept: application/json
Content-Type: application/x-www-form-urlencoded
Authorization: Basic ZGV2Z2xhbi1jbGllbnQ6MTIzNDU2
Cache-Control: no-cache
Postman-Token: 77dd0129-bb86-d039-d252-8e7d483092f2
I debugged the code and indetify that DaoAuthenticationProvider tried to retrive the app client credentials using the user details service.
The question
Why the Spring OAuth use the user details service to authenticate the application clients in oauth authorization flow rather than the in-memory configuration?
My code
Pom.xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-rest</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security.oauth.boot</groupId>
<artifactId>spring-security-oauth2-autoconfigure</artifactId>
<version>2.0.4.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-oauth2-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-oauth2-jose</artifactId>
</dependency>
Application Main
#SpringBootApplication()
#EnableAutoConfiguration
public class Application extends RepositoryRestConfigurerAdapter{
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
The Authorization Server configuration:
#Configuration
#EnableAuthorizationServer
public class ServidorAutorizacaoOAuthConfiguracao extends AuthorizationServerConfigurerAdapter {
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
.withClient("devglan-client")
.secret("$2a$04$e/c1/RfsWuThaWFCrcCuJeoyvwCV0URN/6Pn9ZFlrtIWaU/vj/BfG")
.authorizedGrantTypes("implicit","refresh_token", "password", "authorization_code")
.scopes("read write trust");
}
}
The WebSecurity Configuration:
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled=true)
public class SegurancaConfiguracao extends WebSecurityConfigurerAdapter{
#Autowired
private UsuarioServico usuarioServico;
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(this.usuarioServico).passwordEncoder(encoder());
}
public PasswordEncoder encoder() {
return new BCryptPasswordEncoder();
}
The resource server configuration:
#Configuration
#EnableResourceServer
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class ServidorRecursoOAuthConfiguracao extends
ResourceServerConfigurerAdapter {
public void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.authorizeRequests()
.antMatchers("/api/**").authenticated()
.antMatchers("/oauth2/authorization/google", "/login/oauth2/code/google", "/login").permitAll()
.antMatchers("/oauth/authorize").permitAll()
.anyRequest().permitAll()
.and()
.formLogin()
.and()
.oauth2Login()
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS);
}
}

Categories