Skip to content

Commit

Permalink
Merge pull request #629 from overture-stack/rc/5.1.0
Browse files Browse the repository at this point in the history
5.1.0
use spring security oauth2 client
replace OAuth2SsoFilter with OAuth2AuthorizationRequestResolver bean:
- use oauth2 DSL in SecureServerConfig
- add custom oauth2 and open id connect user info service
- add oauth2 request resolver
replace legacy spring oauth2 beans
add docker compose to run ego stack locally
update docker compose to update keycloak
replace legacy oauth2 lib exceptions
update tests with new changes
  • Loading branch information
blabadi authored Feb 14, 2022
2 parents bc906d5 + 78d9f11 commit 06659a1
Show file tree
Hide file tree
Showing 40 changed files with 816 additions and 963 deletions.
34 changes: 24 additions & 10 deletions docker-compose-all.yml
Original file line number Diff line number Diff line change
@@ -1,31 +1,45 @@
version: '3.7'
services:
ego-ui:
image: overture/ego-ui:edge
expose:
- "8080"
ports:
- "8080:8080"
environment:
REACT_APP_API: http://localhost:8081
REACT_APP_EGO_CLIENT_ID: ego-ui
api:
build:
context: ./
dockerfile: Dockerfile
restart: always
# change the image tag to the target image as needed
image: overture/ego:4c1969bf
environment:
SERVER_PORT: 8080
SERVER_PORT: 8081
SPRING_DATASOURCE_URL: jdbc:postgresql://postgres:5432/ego?stringtype=unspecified
SPRING_DATASOURCE_USERNAME: postgres
SPRING_DATASOURCE_PASSWORD: password
SPRING_FLYWAY_ENABLED: "true"
SPRING_FLYWAY_LOCATIONS: "classpath:flyway/sql,classpath:db/migration"
SPRING_PROFILES: demo, auth
SPRING_PROFILES_ACTIVE: auth
google.client.clientId: $EGO_GOOGLE_CLIENT_ID
google.client.clientSecret: $EGO_GOOGLE_SECRET
default.user.firstUserAsAdmin: "true"
logging.level.root: INFO
expose:
- "8080"
- "8081"
ports:
- "$API_HOST_PORT:8080"
- "8081:8081"
depends_on:
- postgres
postgres:
image: postgres:12.6
restart: always
environment:
- POSTGRES_DB=ego
- POSTGRES_PASSWORD=password
expose:
- "5432"
ports:
- "8432:5432"
- "5432:5432"
volumes:
- "ego_data:/var/lib/postgresql/data"
volumes:
ego_data:
23 changes: 20 additions & 3 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -1,12 +1,26 @@
version: '3.7'
services:
keycloak:
image: quay.io/keycloak/keycloak:16.1.0
ports:
- 8083:8080
environment:
KEYCLOAK_USER: admin
KEYCLOAK_PASSWORD: admin
DB_VENDOR: POSTGRES
DB_ADDR: postgres
DB_DATABASE: ego
DB_USER: postgres
DB_SCHEMA: public
DB_PASSWORD: password
ego-ui:
image: overture/ego-ui:edge
network_mode: host
ports:
- "8080:8080"
environment:
REACT_APP_API: http://localhost:8081
REACT_APP_EGO_CLIENT_ID: ego-ui

REACT_APP_KEYCLOAK_ENABLED: "true"
postgres:
image: postgres:12.6
restart: always
Expand All @@ -17,4 +31,7 @@ services:
- "5432"
ports:
- "5432:5432"

volumes:
- "psql_data:/var/lib/postgresql/data"
volumes:
psql_data:
17 changes: 17 additions & 0 deletions makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
start:
docker-compose -f docker-compose-all.yml up -d
sleep 10;
make init-db

up:
docker-compose -f docker-compose-all.yml up -d

down:
docker-compose -f docker-compose-all.yml down

nuke:
docker-compose -f docker-compose-all.yml down --volumes

# needed to insert the ego ui client in ego db
init-db:
docker exec ego_postgres_1 psql -h localhost -p 5432 -U postgres -d ego --command "INSERT INTO EGOAPPLICATION (name, clientId, clientSecret, redirectUri, description, status, errorredirecturi) VALUES ('ego ui', 'ego-ui', 'secret', 'http://localhost:8080/', '...', 'APPROVED', 'http://localhost:8080/error') on conflict do nothing"
14 changes: 13 additions & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

<groupId>bio.overture</groupId>
<artifactId>ego</artifactId>
<version>5.0.0</version>
<version>5.1.0</version>

<name>ego</name>
<description>OAuth 2.0 Authorization service that supports multiple OpenID Connect Providers</description>
Expand Down Expand Up @@ -48,6 +48,18 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>

<!-- spring security -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-client</artifactId>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package bio.overture.ego.config;

import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.springframework.core.convert.converter.Converter;
import org.springframework.security.oauth2.core.OAuth2AccessToken;
import org.springframework.security.oauth2.core.endpoint.OAuth2AccessTokenResponse;
import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;

// needed for linked in since it doesn't return tokenType in the access token response violating
// oauth2 spec.
// https://github.com/spring-projects/spring-security/issues/5983
public class OAuth2AccessTokenResponseConverterWithDefaults
implements Converter<Map<String, String>, OAuth2AccessTokenResponse> {
private static final Set<String> TOKEN_RESPONSE_PARAMETER_NAMES =
Stream.of(
OAuth2ParameterNames.ACCESS_TOKEN,
OAuth2ParameterNames.TOKEN_TYPE,
OAuth2ParameterNames.EXPIRES_IN,
OAuth2ParameterNames.REFRESH_TOKEN,
OAuth2ParameterNames.SCOPE)
.collect(Collectors.toSet());

private OAuth2AccessToken.TokenType defaultAccessTokenType = OAuth2AccessToken.TokenType.BEARER;

@Override
public OAuth2AccessTokenResponse convert(Map<String, String> tokenResponseParameters) {
String accessToken = tokenResponseParameters.get(OAuth2ParameterNames.ACCESS_TOKEN);

OAuth2AccessToken.TokenType accessTokenType = this.defaultAccessTokenType;
if (OAuth2AccessToken.TokenType.BEARER
.getValue()
.equalsIgnoreCase(tokenResponseParameters.get(OAuth2ParameterNames.TOKEN_TYPE))) {
accessTokenType = OAuth2AccessToken.TokenType.BEARER;
}

long expiresIn = 0;
if (tokenResponseParameters.containsKey(OAuth2ParameterNames.EXPIRES_IN)) {
try {
expiresIn = Long.parseLong(tokenResponseParameters.get(OAuth2ParameterNames.EXPIRES_IN));
} catch (NumberFormatException ignored) {
}
}

Set<String> scopes = Collections.emptySet();
if (tokenResponseParameters.containsKey(OAuth2ParameterNames.SCOPE)) {
String scope = tokenResponseParameters.get(OAuth2ParameterNames.SCOPE);
scopes =
Arrays.stream(StringUtils.delimitedListToStringArray(scope, " "))
.collect(Collectors.toSet());
}

Map<String, Object> additionalParameters = new LinkedHashMap<>();
tokenResponseParameters.entrySet().stream()
.filter(e -> !TOKEN_RESPONSE_PARAMETER_NAMES.contains(e.getKey()))
.forEach(e -> additionalParameters.put(e.getKey(), e.getValue()));

return OAuth2AccessTokenResponse.withToken(accessToken)
.tokenType(accessTokenType)
.expiresIn(expiresIn)
.scopes(scopes)
.additionalParameters(additionalParameters)
.build();
}

public final void setDefaultAccessTokenType(OAuth2AccessToken.TokenType defaultAccessTokenType) {
Assert.notNull(defaultAccessTokenType, "defaultAccessTokenType cannot be null");
this.defaultAccessTokenType = defaultAccessTokenType;
}
}
44 changes: 11 additions & 33 deletions src/main/java/bio/overture/ego/config/OAuth2ClientConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,47 +17,25 @@

package bio.overture.ego.config;

import bio.overture.ego.security.OAuth2ClientResources;
import org.springframework.boot.context.properties.ConfigurationProperties;
import bio.overture.ego.security.CorsFilter;
import bio.overture.ego.security.OAuth2RequestResolver;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository;
import org.springframework.security.oauth2.client.web.OAuth2AuthorizationRequestResolver;

@Configuration
public class OAuth2ClientConfig {

@Bean
@ConfigurationProperties("google")
public OAuth2ClientResources google() {
return new OAuth2ClientResources();
}

@Bean
@ConfigurationProperties("facebook")
public OAuth2ClientResources facebook() {
return new OAuth2ClientResources();
}

@Bean
@ConfigurationProperties("github")
public OAuth2ClientResources github() {
return new OAuth2ClientResources();
}

@Bean
@ConfigurationProperties("linkedin")
public OAuth2ClientResources linkedin() {
return new OAuth2ClientResources();
}

@Bean
@ConfigurationProperties("orcid")
public OAuth2ClientResources orcid() {
return new OAuth2ClientResources();
public OAuth2AuthorizationRequestResolver oAuth2AuthorizationRequestResolver(
ClientRegistrationRepository clientRegistrationRepository) {
return new OAuth2RequestResolver(clientRegistrationRepository, "/oauth/login/");
}

@Bean
@ConfigurationProperties("keycloak")
public OAuth2ClientResources keycloak() {
return new OAuth2ClientResources();
@Primary
public CorsFilter corsFilter() {
return new CorsFilter();
}
}
Loading

0 comments on commit 06659a1

Please sign in to comment.