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>
Related
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.
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.
I'm trying to configure OAuth2 for a Spring project. I used jdbc authentification and my authorization server and resource server are two separate API. My issue is now with the microservices. I'm trying to use this shared authorization server to authenticate the microservices. I can get access_token from the token endpoint.
I can check the access_token from the check_token endpoint.
My resource server configuration:
#SpringBootApplication
#EnableCircuitBreaker
#EnableDiscoveryClient
#EnableResourceServer
public class ProductApiServiceApplication {
public static void main(String[] args) {
SpringApplication.run(ProductApiServiceApplication.class, args);
}
}
And application.yml:
security:
oauth2:
client:
client-id: saba-product-api-service
client-secret: secret123
resource:
id: saba-product-api-service
token-info-uri: http://localhost:9999/uaa/oauth/check_token
And REST controller:
#GetMapping("/user/me")
public Principal user(Principal principal) {
return principal;
}
When I call the /user/me endpoint I get invalid_token.
My Resource Server log:
And my Authorization Server log:
What is wrong with my code?
Update
The problem is because of this code:
I had the same issue. In my case, I was using spring cloud oauth2, Hoxton.SR4 release and it was working. So, I change to Hoxton.SR6 and the issue was throwed. My Authoriation Server also was a Eureka's client, and the issue was origined cause this dependency. There was one dependĂȘncia inside Eureka Client, named jackson-dataformat-xml, and because it the return of check_token endpoint was converted in xml instead json. When RemoteTokenServices called check_token, and the resulta was a xml, it culdn't decerialized in map<String,Object> the right way. If you had more than one aud, scope or authorities, it picked the last one. And the active propertie was trated as string. In my case I solved the issue excluding in Authorization Server the dependency mentioned from Eureka Client, like this:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
<exclusions>
<exclusion>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-xml</artifactId>
</exclusion>
</exclusions>
</dependency>
Finally, I replaced
<dependency>
<groupId>org.springframework.security.oauth</groupId>
<artifactId>spring-security-oauth2</artifactId>
<version>2.3.4.RELEASE</version>
</dependency>
with
<dependency>
<groupId>org.springframework.security.oauth</groupId>
<artifactId>spring-security-oauth2</artifactId>
<version>2.5.0.RELEASE</version>
</dependency>
// gh-838
if (map.containsKey("active") && !"true".equals(String.valueOf(map.get("active")))) {
logger.debug("check_token returned active attribute: " + map.get("active"));
throw new InvalidTokenException(accessToken);
}
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
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);
}
}