Skip to content

Togglz auth #185

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Jun 9, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion conf/WEB-INF/searchBundle.xml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
<property name="name" value="ProjectSearchBundle" />
<property name="context">
<value>
SELECT DISTINCT project.project_id, project_status_lu.project_status_id, project_status_lu.name, project_category_lu.project_category_id, project_category_lu.name, project_type_lu.project_type_id, project_type_lu.name, project.create_user, project.create_date, project.modify_user, project.modify_date FROM project INNER JOIN project_category_lu ON project.project_category_id = project_category_lu.project_category_id INNER JOIN project_status_lu ON project.project_status_id = project_status_lu.project_status_id INNER JOIN project_type_lu ON project_category_lu.project_type_id = project_type_lu.project_type_id INNER JOIN project_info ON project.project_id = project_info.project_id INNER JOIN project_info_type_lu ON project_info.project_info_type_id = project_info_type_lu.project_info_type_id LEFT OUTER JOIN tc_direct_project ON project.tc_direct_project_id = tc_direct_project.project_id WHERE
SELECT DISTINCT project.project_id, project_status_lu.project_status_id, project_status_lu.name as project_status_name, project_category_lu.project_category_id, project_category_lu.name as project_category_name, project_type_lu.project_type_id, project_type_lu.name as project_type_name, project.create_user, project.create_date, project.modify_user, project.modify_date FROM project INNER JOIN project_category_lu ON project.project_category_id = project_category_lu.project_category_id INNER JOIN project_status_lu ON project.project_status_id = project_status_lu.project_status_id INNER JOIN project_type_lu ON project_category_lu.project_type_id = project_type_lu.project_type_id INNER JOIN project_info ON project.project_id = project_info.project_id INNER JOIN project_info_type_lu ON project_info.project_info_type_id = project_info_type_lu.project_info_type_id LEFT OUTER JOIN tc_direct_project ON project.tc_direct_project_id = tc_direct_project.project_id WHERE
</value>
</property>
<property name="alias">
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
package com.cronos.onlinereview.config;

import com.auth0.jwt.interfaces.Claim;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.cronos.onlinereview.util.AuthorizationHelper;
import com.topcoder.onlinereview.component.security.RolePrincipal;
import com.topcoder.onlinereview.component.security.login.LoginBean;
import com.cronos.onlinereview.util.ConfigHelper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
Expand All @@ -14,16 +15,18 @@
import org.togglz.core.user.UserProvider;
import org.togglz.servlet.util.HttpServletRequestHolder;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.util.List;
import java.util.Set;

public class TogglzConfiguration implements TogglzConfig {
private static final Logger logger = LoggerFactory.getLogger(TogglzConfiguration.class);

@Value("#{'${togglz.roles}'.split(',')}")
private List<String> roles;
@Value("${togglz.role_key}")
private String roleKey;

public Class<? extends Feature> getFeatureClass() {
return TogglzFeatures.class;
Expand All @@ -36,10 +39,25 @@ public StateRepository getStateRepository() {
public UserProvider getUserProvider() {
return () -> {
HttpServletRequest request = HttpServletRequestHolder.get();
Set<RolePrincipal> roleSet = LoginBean.getUserRoles(AuthorizationHelper.getLoggedInUserId(request));
for (RolePrincipal role : roleSet) {
if (roles.contains(role.getName())) {
return new SimpleFeatureUser("admin", true);
Cookie[] cookies = request.getCookies();
if (cookies != null) {
for (Cookie c : cookies) {
if (c.getName().equals(ConfigHelper.getV2jwtCookieName())) {
DecodedJWT jwt;
try {
jwt = AuthorizationHelper.validateJWTToken(c.getValue());
} catch (Exception e) {
return new SimpleFeatureUser("user", false);
}
Claim claim = jwt.getClaim(roleKey);
if (claim != null) {
for (String role : claim.asArray(String.class)) {
if (roles.contains(role)) {
return new SimpleFeatureUser("admin", true);
}
}
}
}
}
}
return new SimpleFeatureUser("user", false);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,25 @@
*/
package com.cronos.onlinereview.util;

import com.auth0.jwk.GuavaCachedJwkProvider;
import com.auth0.jwk.Jwk;
import com.auth0.jwk.JwkProvider;
import com.auth0.jwk.UrlJwkProvider;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTDecodeException;
import com.auth0.jwt.exceptions.SignatureVerificationException;
import com.auth0.jwt.exceptions.TokenExpiredException;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.auth0.jwt.interfaces.Verification;
import com.cronos.onlinereview.Constants;
import com.topcoder.onlinereview.component.dataaccess.ProjectDataAccess;
import com.topcoder.onlinereview.component.exception.BaseException;
import com.topcoder.onlinereview.component.external.ExternalUser;
import com.topcoder.onlinereview.component.external.UserRetrieval;
import com.topcoder.onlinereview.component.jwt.InvalidTokenException;
import com.topcoder.onlinereview.component.jwt.JWTException;
import com.topcoder.onlinereview.component.project.management.Project;
import com.topcoder.onlinereview.component.project.management.ProjectManager;
import com.topcoder.onlinereview.component.resource.Resource;
Expand All @@ -22,7 +36,10 @@
import org.springframework.web.context.support.WebApplicationContextUtils;

import javax.servlet.http.HttpServletRequest;

import java.security.interfaces.RSAPublicKey;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import static com.topcoder.onlinereview.component.util.SpringUtils.getBean;
Expand Down Expand Up @@ -468,4 +485,67 @@ public void setSsoCookieService(SSOCookieService ssoCookieService) {
AuthorizationHelper.ssoCookieService = ssoCookieService;
}

/**
* <p>
* Validate jwt token
* </p>
*
* @param token the jwt token
* @throws JWTException if any error occurs
* @return the DecodedJWT result
*/
public static DecodedJWT validateJWTToken(String token) throws JWTException {
if (token == null) {
throw new IllegalArgumentException("token must be specified.");
}
DecodedJWT decodedJWT = null;
// Decode only first to get the algorithm
try {
decodedJWT = JWT.decode(token);
} catch (JWTDecodeException e) {
throw new InvalidTokenException(token, "Error occurred in decoding token. " + e.getLocalizedMessage(), e);
}
String algorithm = decodedJWT.getAlgorithm();
Algorithm alg = null;
// Create the algorithm
if ("RS256".equals(algorithm)) {
List<String> validIssuers = ConfigHelper.getValidIssuers();
// Validate the issuer
if (decodedJWT.getIssuer() == null || !validIssuers.contains(decodedJWT.getIssuer())) {
throw new InvalidTokenException(token, "Invalid issuer: " + decodedJWT.getIssuer());
}

// Create the JWK provider with caching
JwkProvider urlJwkProvider = new UrlJwkProvider(decodedJWT.getIssuer());
JwkProvider jwkProvider = new GuavaCachedJwkProvider(urlJwkProvider);

// Get the public key and create the algorithm
try {
Jwk jwk = jwkProvider.get(decodedJWT.getKeyId());
RSAPublicKey publicKey = (RSAPublicKey) jwk.getPublicKey();

alg = Algorithm.RSA256(publicKey, null);
} catch (Exception e) {
throw new JWTException(token, "Error occurred in creating algorithm. " + e.getLocalizedMessage(), e);
}
} else {
throw new JWTException(token, "Algorithm not supported: " + algorithm);
}

// Verify
try {
Verification verification = JWT.require(alg);

JWTVerifier verifier = verification.build();
decodedJWT = verifier.verify(token);
} catch (TokenExpiredException e) {
throw new TokenExpiredException(token);
} catch (SignatureVerificationException | IllegalStateException e) {
throw new InvalidTokenException(token, "Token is invalid. " + e.getLocalizedMessage(), e);
} catch (Exception e) {
throw new JWTException(token, "Error occurred in verifying token. " + e.getLocalizedMessage(), e);
}
return decodedJWT;
}

}
26 changes: 26 additions & 0 deletions src/main/java/com/cronos/onlinereview/util/ConfigHelper.java
Original file line number Diff line number Diff line change
Expand Up @@ -596,6 +596,11 @@ public class ConfigHelper {
*/
private static final String V3_JWT_AUTHORIZATION_URL = "v3jwt_authorization_url";

/**
* <p>A <code>String</code> providing the list of valid issuers</p>
*/
private static final String VALID_ISSUERS = "valid_issuers";

/**
* This member variable holds the submitter role id.
*/
Expand Down Expand Up @@ -972,6 +977,11 @@ public class ConfigHelper {
*/
private static String v3jwtAuthorizationUrl;

/**
* <p>A <code>List</code> for the valid issuers</p>
*/
private static final List<String> validIssuers = new ArrayList<String>();

/**
* <p>Represents the ssoDomainForV3jwtCookie.</p>
*/
Expand Down Expand Up @@ -1662,6 +1672,14 @@ public class ConfigHelper {
v2jwtCookieName = cfgMgr.getString(ONLINE_REVIEW_CFG_NS, V2_JWT_COOKIE_NAME);
ssoDomainForV3jwtCookie = cfgMgr.getString(ONLINE_REVIEW_CFG_NS, SSO_DOMAIN_FOR_V3_JWT_COOKIE);
v3jwtAuthorizationUrl = cfgMgr.getString(ONLINE_REVIEW_CFG_NS, V3_JWT_AUTHORIZATION_URL);
// Read the valid issuers property
String validIssuersProperty = cfgMgr.getString(ONLINE_REVIEW_CFG_NS, VALID_ISSUERS);
if (validIssuersProperty != null && validIssuersProperty.trim().length() != 0) {
String[] validIssuerStrings = validIssuersProperty.split(",");
for (String validIssuer : validIssuerStrings) {
validIssuers.add(validIssuer.trim());
}
}

ConfigManager.Property eventBus = cfgMgr.getPropertyObject(ONLINE_REVIEW_CFG_NS, "event_bus");
contestSubmissionDownloadUrl = eventBus.getValue("contestSubmissionDownloadUrl");
Expand Down Expand Up @@ -2535,6 +2553,14 @@ public static String getV3jwtAuthorizationUrl() {
return v3jwtAuthorizationUrl;
}

/**
* Get valid issuers.
* @return the valid issuers list.
*/
public static List<String> getValidIssuers() {
return validIssuers;
}

/**
* Get ssoDomainForV3jwtCookie.
* @return the ssoDomainForV3jwtCookie.
Expand Down
3 changes: 2 additions & 1 deletion src/main/resources/applicationConfig.properties
Original file line number Diff line number Diff line change
Expand Up @@ -49,4 +49,5 @@ workday.end_time_minutes=0
workday.locale.language=en
workday.locale.country=US

togglz.roles=Admin Super Role,Admin Regular Role
togglz.roles=administrator
togglz.role_key=https://topcoder-dev.com/roles
3 changes: 3 additions & 0 deletions src/main/resources/config.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2074,6 +2074,9 @@
<Property name="sso_domain_for_v3jwt_cookie">
<Value>.topcoder.com</Value>
</Property>
<Property name="valid_issuers">
<Value>@valid_issuers@</Value>
</Property>

<Property name="event_bus">
<Property name="topic">
Expand Down
3 changes: 2 additions & 1 deletion token.properties.local
Original file line number Diff line number Diff line change
Expand Up @@ -272,4 +272,5 @@ aws_s3_access_key=AKIAIZNXS3HERHTLVQKA
aws_s3_secret_key=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

topcoder_event_bus_auth_proxy_server_url=https://auth0proxy.topcoder-dev.com/token
new_auth_url=https://accounts-auth0.topcoder-dev.com
new_auth_url=https://accounts-auth0.topcoder-dev.com
valid_issuers=https://api.topcoder-dev.com,https://api.topcoder.com,https://topcoder-dev.auth0.com/,https://auth.topcoder-dev.com/