Skip to content

Commit

Permalink
feat: implement custom resolvers for custom auth over oauth2
Browse files Browse the repository at this point in the history
  • Loading branch information
Aiosa committed Oct 8, 2024
1 parent 74516be commit 0aa380d
Show file tree
Hide file tree
Showing 10 changed files with 374 additions and 32 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -42,25 +42,27 @@
* Interface to use to retrieve
* portal user information.
*/
public interface SecurityRepository {
public interface SecurityRepository<AuthUserContext> {

/**
* Given a user id, returns a user instance.
* If username does not exist in db, returns null.
*
* @param username String
* @param user object that has necessary user information
* @return User
*/
User getPortalUser(String username);
User getPortalUser(String username, AuthUserContext user);

/**
* Given a user id, returns a UserAuthorities instance.
* If username does not exist in db, returns null.
*
* @param username String
* @param user object that has necessary user information
* @return UserAuthorities
*/
UserAuthorities getPortalUserAuthorities(String username);
UserAuthorities getPortalUserAuthorities(String username, AuthUserContext user);

void addPortalUser(User user);
void addPortalUserAuthorities(UserAuthorities userAuthorities);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,13 +64,4 @@ public interface SecurityMapper {

void addPortalUser(User user);
void addPortalUserAuthority(@Param("email") String email, @Param("authority") String authority);

/**
* Given an internal cancer study id, returns groups string.
* Returns null if cancer study does not exist.
*
* @param internalCancerStudyId Integer
* @return String groups
*/
String getCancerStudyGroups(Integer internalCancerStudyId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -45,26 +45,31 @@
import org.cbioportal.model.UserAuthorities;
import org.cbioportal.persistence.SecurityRepository;

import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

@Repository
public class SecurityMyBatisRepository implements SecurityRepository {
@ConditionalOnProperty(name = "security.repository.type", havingValue = "cbioportal", matchIfMissing = true)
public class SecurityMyBatisRepository implements SecurityRepository<Object> {

private static final Logger log = LoggerFactory.getLogger(SecurityMyBatisRepository.class);

@Autowired
private SecurityMapper securityMapper;

@Autowired
private StudyGroupMapper studyGroupMapper;

/**
* Given a user id, returns a user instance.
* If username does not exist in db, returns null.
*
* @param username String
* @param _unused
* @return User
*/
@Override
public User getPortalUser(String username) {
public User getPortalUser(String username, Object _unused) {
User user = securityMapper.getPortalUser(username);
if (user != null) {
log.debug("User " + username + " was found in the users table, email is " + user.getEmail());
Expand All @@ -79,10 +84,11 @@ public User getPortalUser(String username) {
* If username does not exist in db, returns null.
*
* @param username String
* @param _unused
* @return UserAuthorities
*/
@Override
public UserAuthorities getPortalUserAuthorities(String username) {
public UserAuthorities getPortalUserAuthorities(String username, Object _unused) {
return securityMapper.getPortalUserAuthorities(username);
}

Expand All @@ -107,7 +113,7 @@ public void addPortalUserAuthorities(UserAuthorities userAuthorities) {
*/
@Override
public Set<String> getCancerStudyGroups(Integer internalCancerStudyId) {
String groups = securityMapper.getCancerStudyGroups(internalCancerStudyId);
String groups = studyGroupMapper.getCancerStudyGroups(internalCancerStudyId);
if (groups == null) {
return Collections.emptySet();
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/*
* Copyright (c) 2015 Memorial Sloan-Kettering Cancer Center.
*
* This library is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS
* FOR A PARTICULAR PURPOSE. The software and documentation provided hereunder
* is on an "as is" basis, and Memorial Sloan-Kettering Cancer Center has no
* obligations to provide maintenance, support, updates, enhancements or
* modifications. In no event shall Memorial Sloan-Kettering Cancer Center be
* liable to any party for direct, indirect, special, incidental or
* consequential damages, including lost profits, arising out of the use of this
* software and its documentation, even if Memorial Sloan-Kettering Cancer
* Center has been advised of the possibility of such damage.
*/

/*
* This file is part of cBioPortal.
*
* cBioPortal is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

package org.cbioportal.persistence.mybatis;

// imports
import org.apache.ibatis.annotations.Param;

/**
* Interface to use to retrieve
* portal user information.
*/
public interface StudyGroupMapper {
/**
* Given an internal cancer study id, returns groups string.
* Returns null if cancer study does not exist.
*
* @param internalCancerStudyId Integer
* @return String groups
*/
String getCancerStudyGroups(Integer internalCancerStudyId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
import org.springframework.security.oauth2.core.oidc.user.DefaultOidcUser;
import org.springframework.security.oauth2.core.oidc.user.OidcUser;
import org.springframework.security.oauth2.core.oidc.OidcIdToken;

import java.util.HashSet;
import java.util.Objects;
Expand All @@ -29,12 +30,12 @@
public class CustomOAuth2AuthorizationConfig {
Logger log = LoggerFactory.getLogger(CustomOAuth2AuthorizationConfig.class);

private final SecurityRepository securityRepository;
private final SecurityRepository<OidcUser> securityRepository;

private static final String NAME_ATTRIBUTE_KEY = "email";

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

Expand All @@ -48,9 +49,9 @@ public OAuth2UserService<OidcUserRequest, OidcUser> oidcUserService() {
// Delegate to the default implementation for loading a user
OidcUser oidcUser = delegate.loadUser(userRequest);

var authenticatedPortalUser = loadPortalUser(oidcUser.getEmail());
var authenticatedPortalUser = loadPortalUser(oidcUser.getEmail(), oidcUser);
if (Objects.isNull(authenticatedPortalUser.cbioUser) || !authenticatedPortalUser.cbioUser.isEnabled()) {
log.debug("User: {} either not in db or not authorized", oidcUser.getEmail());
log.error("User: {} either not in db or not authorized", oidcUser.getEmail());
throw new OAuth2AuthenticationException("user not authorized");
}
Set<GrantedAuthority> mappedAuthorities = authenticatedPortalUser.authorities;
Expand All @@ -59,11 +60,11 @@ public OAuth2UserService<OidcUserRequest, OidcUser> oidcUserService() {
};
}

private AuthenticatedPortalUser loadPortalUser(String email) {
private AuthenticatedPortalUser loadPortalUser(String username, OidcUser user) {
Set<GrantedAuthority> mappedAuthorities = new HashSet<>();
User cbioUser = securityRepository.getPortalUser(email);
User cbioUser = securityRepository.getPortalUser(username, user);
if (!Objects.isNull(cbioUser)) {
UserAuthorities authorities = securityRepository.getPortalUserAuthorities(email);
UserAuthorities authorities = securityRepository.getPortalUserAuthorities(username, user);
if (!Objects.isNull(authorities)) {
mappedAuthorities.addAll(AuthorityUtils.createAuthorityList(authorities.getAuthorities()));
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
/*
* Copyright (c) 2015 Memorial Sloan-Kettering Cancer Center.
*
* This library is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS
* FOR A PARTICULAR PURPOSE. The software and documentation provided hereunder
* is on an "as is" basis, and Memorial Sloan-Kettering Cancer Center has no
* obligations to provide maintenance, support, updates, enhancements or
* modifications. In no event shall Memorial Sloan-Kettering Cancer Center be
* liable to any party for direct, indirect, special, incidental or
* consequential damages, including lost profits, arising out of the use of this
* software and its documentation, even if Memorial Sloan-Kettering Cancer
* Center has been advised of the possibility of such damage.
*/

/*
* This file is part of cBioPortal.
*
* cBioPortal is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

package org.cbioportal.security.config.access;

// imports
import java.util.Arrays;
import java.util.Collections;
import java.util.Set;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import org.cbioportal.model.User;
import org.cbioportal.model.UserAuthorities;
import org.cbioportal.persistence.SecurityRepository;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;

import org.springframework.stereotype.Service;

@Service
@ConditionalOnProperty(name = "security.repository.type", havingValue = "disabled")
public class FullAccessResolver implements SecurityRepository<Object> {

private static final Logger log = LoggerFactory.getLogger(FullAccessResolver.class);

/**
* Always returns a valid user.
*
* @param username String
* @param user Object
* @return User
*/
@Override
public User getPortalUser(String username, Object user) {
return new User(username, username, true);
}

/**
* Given a user id, returns a UserAuthorities instance.
* If username does not exist in db, returns null.
*
* @param username String
* @param user Object
* @return UserAuthorities
*/
@Override
public UserAuthorities getPortalUserAuthorities(String username, Object user) {
return new UserAuthorities();
}

@Override
public void addPortalUser(User user) {
//no-op
}

@Override
public void addPortalUserAuthorities(UserAuthorities userAuthorities) {
//no-op
}

/**
* Given an internal cancer study id, returns a set of upper case cancer study group strings.
* Returns empty set if cancer study does not exist or there are no groups.
*
* @param internalCancerStudyId Integer
* @return Set<String> cancer study group strings in upper case
*/
@Override
public Set<String> getCancerStudyGroups(Integer internalCancerStudyId) {
return Collections.emptySet();
}
}
Loading

0 comments on commit 0aa380d

Please sign in to comment.