Skip to content

Commit

Permalink
Add updates to spring security config (#10549)
Browse files Browse the repository at this point in the history
* Add updates to spring security config

* Add back InactiveCacheMap and add optional_oauth2 to AutoCofigExclude class

* Fix DataAccessTokenController Test

* Copy Application Properties for Integration Test

* Update LoginController to have support for post and get

* Add Custom Authorization and force oauth2 through login page... redirects to single idp if there is only one

* Fix CacheMap Annotations

* Force Method Auth if using oauth2 or saml

* Add UUID Token AuthenticationProvider

* Update to make method_authorization property only applicable when optional_oauth2 is set

* Add Redirect when one idp is set

* Fix Sonar issues

* Remove unused imports

* 🐛 fix SAML2 Config
  • Loading branch information
haynescd authored Jan 22, 2024
1 parent cf65392 commit e4719bf
Show file tree
Hide file tree
Showing 22 changed files with 240 additions and 316 deletions.
4 changes: 4 additions & 0 deletions .github/workflows/security-integration-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ jobs:
- name: 'Add host.testcontainers.internal to /etc/hosts'
run: |
echo "127.0.0.1 host.testcontainers.internal" | sudo tee -a /etc/hosts
- name: 'Copy Application.Properties'
working-directory: ./cbioportal
run: |
cp src/main/resources/application.properties.EXAMPLE src/main/resources/application.properties
- name: 'Run integration tests'
working-directory: ./cbioportal
run: |
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package org.cbioportal.persistence.cachemaputil;

import org.cbioportal.model.CancerStudy;
import org.cbioportal.model.MolecularProfile;
import org.cbioportal.model.SampleList;
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
import org.springframework.stereotype.Component;

import java.util.Map;

@Component
// This implementation of the CacheMapUtils is instantiated on portals where all uses can access any study.
@ConditionalOnExpression("'false' eq '${authenticate}' or ('optional_oauth2' eq '${authenticate}' and 'true' ne '${security.method_authorization_enabled}')")
public class InactiveCacheMapUtil implements CacheMapUtil {

// Since user-permission evaluation is not needed when this bean is present, throw an error when it is accessed.

@Override
public Map<String, MolecularProfile> getMolecularProfileMap() {
throw new RuntimeException("A CacheMapUtils method was called on a portal where studies are accessible to all users.");
}

@Override
public Map<String, SampleList> getSampleListMap() {
throw new RuntimeException("A CacheMapUtils method was called on a portal where studies are accessible to all users.");
}

@Override
public Map<String, CancerStudy> getCancerStudyMap() {
throw new RuntimeException("A CacheMapUtils method was called on a portal where studies are accessible to all users.");
}

// bean is only instantiated when there is no user authorization
@Override
public boolean hasCacheEnabled() {
return false;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -41,14 +41,16 @@
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Component;

import java.util.Map;

@Component
// Instantiate when user authorization is active and spring-managed implementation is needed
@ConditionalOnExpression("${security.method_authorization_enabled:false} and ${cache.cache-map-utils.spring-managed:false}")
@ConditionalOnExpression("{'oauth2','saml'}.contains('${authenticate}') or ('optional_oauth2' eq '${authenticate}' and 'true' eq '${security.method_authorization_enabled}')")
@ConditionalOnProperty(value = "cache.cache-map-utils.spring-managed", havingValue = "true")
public class SpringManagedCacheMapUtil implements CacheMapUtil {

private static final Logger LOG = LoggerFactory.getLogger(SpringManagedCacheMapUtil.class);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,13 +40,15 @@
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Component;

import java.util.Map;

@Component
// Instantiate when user authorization is active and spring-managed implementation is not needed
@ConditionalOnExpression("${security.method_authorization_enabled:false} and !${cache.cache-map-utils.spring-managed:false}")
@ConditionalOnExpression("{'oauth2','saml'}.contains('${authenticate}') or ('optional_oauth2' eq '${authenticate}' and 'true' eq '${security.method_authorization_enabled}')")
@ConditionalOnProperty(value = "cache.cache-map-utils.spring-managed", havingValue = "false", matchIfMissing = true)
public class StaticRefCacheMapUtil implements CacheMapUtil {

private static final Logger LOG = LoggerFactory.getLogger(StaticRefCacheMapUtil.class);
Expand Down

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
import org.springframework.security.web.context.SecurityContextPersistenceFilter;

@Configuration
@ConditionalOnProperty(name = "authenticate", havingValue = {"false", "noauthsessionservice"}, isNot = true)
@ConditionalOnProperty(name = "authenticate", havingValue = {"false", "noauthsessionservice", "optional_oauth2"}, isNot = true)
public class ApiSecurityConfig {

// Add security filter chains that handle calls to the API endpoints.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
public class AutoconfigureExcludeConfig {

@Configuration
@ConditionalOnProperty(name = "authenticate", havingValue = {"saml", "oauth2"}, isNot = true)
@ConditionalOnProperty(name = "authenticate", havingValue = {"saml", "oauth2", "optional_oauth2"}, isNot = true)
@EnableAutoConfiguration(exclude={OAuth2ClientAutoConfiguration.class, Saml2RelyingPartyAutoConfiguration.class})
public static class ExcludeAll {}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,52 +28,51 @@
@ConditionalOnProperty(value = "authorization", havingValue = "true")
public class CustomOAuth2AuthorizationConfig {
Logger log = LoggerFactory.getLogger(CustomOAuth2AuthorizationConfig.class);

private final SecurityRepository securityRepository;

private static final String NAME_ATTRIBUTE_KEY = "email";

@Autowired
public CustomOAuth2AuthorizationConfig(SecurityRepository securityRepository) {
this.securityRepository = securityRepository;
this.securityRepository = securityRepository;
}

@Bean
public OAuth2UserService<OidcUserRequest, OidcUser> oidcUserService() {
public OAuth2UserService<OidcUserRequest, OidcUser> oidcUserService() {
final OidcUserService delegate = new OidcUserService();

return userRequest -> {
log.debug("Custom OAuth2 Authorization Enabled");

// Delegate to the default implementation for loading a user
OidcUser oidcUser = delegate.loadUser(userRequest);

var authenticatedPortalUser = loadPortalUser(oidcUser.getEmail());
var authenticatedPortalUser = loadPortalUser(oidcUser.getEmail());
if (Objects.isNull(authenticatedPortalUser.cbioUser) || !authenticatedPortalUser.cbioUser.isEnabled()) {
log.debug("User: {} either not in db or not authorized", oidcUser.getEmail());
throw new OAuth2AuthenticationException("user not authorized");
}
Set<GrantedAuthority> mappedAuthorities = authenticatedPortalUser.authorities;
Set<GrantedAuthority> mappedAuthorities = authenticatedPortalUser.authorities;
oidcUser = new DefaultOidcUser(mappedAuthorities, oidcUser.getIdToken(), oidcUser.getUserInfo(), NAME_ATTRIBUTE_KEY);

return oidcUser;
};
}

private AuthenticatedPortalUser loadPortalUser(String email) {
Set<GrantedAuthority> mappedAuthorities = new HashSet<>();
User cbioUser = securityRepository.getPortalUser(email);
if (!Objects.isNull(cbioUser)) {
UserAuthorities authorities = securityRepository.getPortalUserAuthorities(email);
if (!Objects.isNull(authorities)) {
mappedAuthorities.addAll(AuthorityUtils.createAuthorityList(authorities.getAuthorities()));
mappedAuthorities.addAll(AuthorityUtils.createAuthorityList(authorities.getAuthorities()));
}
}
return new AuthenticatedPortalUser(cbioUser, mappedAuthorities);
}

record AuthenticatedPortalUser(User cbioUser, Set<GrantedAuthority> authorities) {

}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,8 @@
import org.cbioportal.persistence.cachemaputil.CacheMapUtil;
import org.cbioportal.security.CancerStudyPermissionEvaluator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler;
Expand All @@ -15,9 +13,8 @@

@Configuration
@EnableMethodSecurity(prePostEnabled = true)
@ConditionalOnExpression("{'oauth2','saml','optional_oauth2'}.contains('${authenticate}')")
//TODO: Potentially Delete after import pipeline fixed
@ConditionalOnProperty(name = "security.method_authorization_enabled", havingValue = "true")
// TODO: We are allowing users to enable method_authorization if optional_oauth2 is selected
@ConditionalOnExpression("{'oauth2','saml'}.contains('${authenticate}') or ('optional_oauth2' eq '${authenticate}' and 'true' eq '${security.method_authorization_enabled}')")
public class MethodSecurityConfig {
@Value("${app.name:}")
private String appName;
Expand Down
Loading

0 comments on commit e4719bf

Please sign in to comment.