Skip to content

Commit

Permalink
catalog: methods to update federation server/client params, #TASK-7192
Browse files Browse the repository at this point in the history
  • Loading branch information
pfurio committed Jan 16, 2025
1 parent 9b0464a commit fbd759b
Show file tree
Hide file tree
Showing 24 changed files with 329 additions and 105 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.annotation.Nullable;
import javax.crypto.spec.SecretKeySpec;
import java.io.Closeable;
import java.security.Key;
Expand Down Expand Up @@ -78,6 +79,20 @@ Key converStringToKeyObject(String keyString, String jcaAlgorithm) {
public abstract AuthenticationResponse authenticate(String organizationId, String userId, String password)
throws CatalogAuthenticationException;

/**
* Authenticate the user against the Authentication server.
*
* @param organizationId Organization id.
* @param userId User to authenticate
* @param password Password.
* @param secretKey Secret key to apply to the token.
* @return AuthenticationResponse object.
* @throws CatalogAuthenticationException CatalogAuthenticationException if any of the credentials are wrong or the access is denied
* for any other reason.
*/
public abstract AuthenticationResponse authenticate(String organizationId, String userId, String password, String secretKey)
throws CatalogAuthenticationException;

/**
* Authenticate the user against the Authentication server.
*
Expand All @@ -95,6 +110,25 @@ public AuthenticationResponse refreshToken(String refreshToken) throws CatalogAu
}
}

/**
* Validates that the token is valid.
*
* @param token token that have been assigned to a user.
* @param secretKey secret key to be used for the token validation (may be null).
* @throws CatalogAuthenticationException when the token does not correspond to any user, is expired or has been altered.
*/
public void validateToken(String token, @Nullable String secretKey) throws CatalogAuthenticationException {
if (StringUtils.isEmpty(token) || "null".equalsIgnoreCase(token)) {
throw new CatalogAuthenticationException("Token is null or empty.");
}
Key privateKey = null;
if (secretKey != null) {
privateKey = converStringToKeyObject(secretKey, jwtManager.getAlgorithm().getJcaName());
}

jwtManager.validateToken(token, privateKey);
}

/**
* Obtains the userId corresponding to the token.
*
Expand Down Expand Up @@ -174,20 +208,20 @@ public abstract void changePassword(String organizationId, String userId, String
* @return A token.
*/
public String createToken(String organizationId, String userId) throws CatalogAuthenticationException {
return createToken(organizationId, userId, Collections.emptyMap(), expiration);
return createToken(organizationId, userId, Collections.emptyMap(), expiration, (Key) null);
}

/**
* Create a token for the user with default expiration time.
*
* @param organizationId Organization id.
* @param userId user.
* @param expiration expiration time.
* @param secretKey secret key to be used for the token generation.
* @throws CatalogAuthenticationException CatalogAuthenticationException
* @return A token.
*/
public String createToken(String organizationId, String userId, long expiration) throws CatalogAuthenticationException {
return createToken(organizationId, userId, Collections.emptyMap(), expiration);
public String createToken(String organizationId, String userId, String secretKey) throws CatalogAuthenticationException {
return createToken(organizationId, userId, Collections.emptyMap(), expiration, secretKey);
}

/**
Expand All @@ -200,7 +234,57 @@ public String createToken(String organizationId, String userId, long expiration)
* @return A token.
*/
public String createToken(String organizationId, String userId, Map<String, Object> claims) throws CatalogAuthenticationException {
return createToken(organizationId, userId, claims, expiration);
return createToken(organizationId, userId, claims, expiration, (Key) null);
}

/**
* Create a token for the user with default expiration time.
*
* @param organizationId Organization id.
* @param userId user.
* @param claims claims.
* @param secretKey secret key to be used for the token generation.
* @throws CatalogAuthenticationException CatalogAuthenticationException
* @return A token.
*/
public String createToken(String organizationId, String userId, Map<String, Object> claims, String secretKey)
throws CatalogAuthenticationException {
return createToken(organizationId, userId, claims, expiration, secretKey);
}

/**
* Create a token for the user.
*
* @param organizationId Organization id.
* @param userId user.
* @param claims claims.
* @param expiration Expiration time in seconds.
* @throws CatalogAuthenticationException CatalogAuthenticationException
* @return A token.
*/
public String createToken(String organizationId, String userId, Map<String, Object> claims, long expiration)
throws CatalogAuthenticationException {
return createToken(organizationId, userId, claims, expiration, (Key) null);
}

/**
* Create a token for the user.
*
* @param organizationId Organization id.
* @param userId user.
* @param claims claims.
* @param expiration Expiration time in seconds.
* @param secretKey Secret key to be used for the token generation.
* @throws CatalogAuthenticationException CatalogAuthenticationException
* @return A token.
*/
public String createToken(String organizationId, String userId, Map<String, Object> claims, long expiration, String secretKey)
throws CatalogAuthenticationException {
Key privateKey = null;
if (secretKey != null) {
privateKey = converStringToKeyObject(secretKey, jwtManager.getAlgorithm().getJcaName());
}
return createToken(organizationId, userId, claims, expiration, privateKey);
}

/**
Expand All @@ -210,10 +294,11 @@ public String createToken(String organizationId, String userId, Map<String, Obje
* @param userId user.
* @param claims claims.
* @param expiration Expiration time in seconds.
* @param secretKey Secret key to be used for the token generation.
* @throws CatalogAuthenticationException CatalogAuthenticationException
* @return A token.
*/
public abstract String createToken(String organizationId, String userId, Map<String, Object> claims, long expiration)
public abstract String createToken(String organizationId, String userId, Map<String, Object> claims, long expiration, Key secretKey)
throws CatalogAuthenticationException;

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.security.Key;
import java.security.PublicKey;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
Expand Down Expand Up @@ -260,6 +261,12 @@ public AuthenticationResponse authenticate(String organizationId, String userId,
}
}

@Override
public AuthenticationResponse authenticate(String organizationId, String userId, String password, String secretKey)
throws CatalogAuthenticationException {
throw new UnsupportedOperationException("AzureAD creates its own tokens. Please, call to the other authenticate method.");
}

@Override
public AuthenticationResponse refreshToken(String refreshToken) throws CatalogAuthenticationException {
AuthenticationContext context;
Expand Down Expand Up @@ -422,7 +429,7 @@ public void newPassword(String organizationId, String userId, String newPassword
}

@Override
public String createToken(String organizationId, String userId, Map<String, Object> claims, long expiration) {
public String createToken(String organizationId, String userId, Map<String, Object> claims, long expiration, Key secretKey) {
// Tokens are generated by Azure via authorization code or user-password
throw new UnsupportedOperationException("Tokens are generated by Azure via authorization code or user-password");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,17 @@ public AuthenticationResponse authenticate(String organizationId, String userId,
}
}

@Override
public AuthenticationResponse authenticate(String organizationId, String userId, String password, String secretKey)
throws CatalogAuthenticationException {
try {
dbAdaptorFactory.getCatalogUserDBAdaptor(organizationId).authenticate(userId, password);
return new AuthenticationResponse(createToken(organizationId, userId, secretKey));
} catch (CatalogDBException e) {
throw new CatalogAuthenticationException("Could not validate '" + userId + "' password\n" + e.getMessage(), e);
}
}

@Override
public List<User> getUsersFromRemoteGroup(String group) throws CatalogException {
throw new UnsupportedOperationException();
Expand All @@ -110,18 +121,19 @@ public void newPassword(String organizationId, String userId, String newPassword
}

@Override
public String createToken(String organizationId, String userId, Map<String, Object> claims, long expiration)
public String createToken(String organizationId, String userId, Map<String, Object> claims, long expiration, Key secretKey)
throws CatalogAuthenticationException {
List<JwtPayload.FederationJwtPayload> federations = getFederations(organizationId, userId);
return jwtManager.createJWTToken(organizationId, AuthenticationOrigin.AuthenticationType.OPENCGA, userId, claims, federations,
expiration);
secretKey, expiration);
}

@Override
public String createNonExpiringToken(String organizationId, String userId, Map<String, Object> claims)
throws CatalogAuthenticationException {
List<JwtPayload.FederationJwtPayload> federations = getFederations(organizationId, userId);
return jwtManager.createJWTToken(organizationId, AuthenticationOrigin.AuthenticationType.OPENCGA, userId, claims, federations, 0L);
return jwtManager.createJWTToken(organizationId, AuthenticationOrigin.AuthenticationType.OPENCGA, userId, claims, federations,
null, 0L);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,8 @@ public JwtManager setPublicKey(Key publicKey) {
}

public String createJWTToken(String organizationId, AuthenticationOrigin.AuthenticationType type, String userId,
Map<String, Object> claims, List<JwtPayload.FederationJwtPayload> federations, long expiration) {
Map<String, Object> claims, List<JwtPayload.FederationJwtPayload> federations, Key secretKey,
long expiration) {
long currentTime = System.currentTimeMillis();

JwtBuilder jwtBuilder = Jwts.builder();
Expand All @@ -108,7 +109,7 @@ public String createJWTToken(String organizationId, AuthenticationOrigin.Authent
.setAudience(organizationId)
.setIssuer("OpenCGA")
.setIssuedAt(new Date(currentTime))
.signWith(privateKey, algorithm);
.signWith(secretKey != null ? secretKey : privateKey, algorithm);

// Set the expiration in number of seconds only if 'expiration' is greater than 0
if (expiration > 0) {
Expand All @@ -119,15 +120,15 @@ public String createJWTToken(String organizationId, AuthenticationOrigin.Authent
}

public void validateToken(String token) throws CatalogAuthenticationException {
validateToken(token, this.publicKey);
parseClaims(token);
}

public void validateToken(String token, Key publicKey) throws CatalogAuthenticationException {
parseClaims(token, publicKey);
}

public JwtPayload getPayload(String token) throws CatalogAuthenticationException {
Claims body = parseClaims(token, publicKey).getBody();
Claims body = parseClaims(token).getBody();
return new JwtPayload(body.getSubject(), body.getAudience(), getAuthOrigin(body), body.getIssuer(), body.getIssuedAt(),
body.getExpiration(), JwtUtils.getFederations(body), token);
}
Expand Down Expand Up @@ -164,7 +165,7 @@ public String getUser(String token, Key publicKey) throws CatalogAuthenticationE
}

public String getUser(String token, String fieldKey) throws CatalogAuthenticationException {
return String.valueOf(parseClaims(token, publicKey).getBody().get(fieldKey));
return String.valueOf(parseClaims(token).getBody().get(fieldKey));
}

public List<String> getGroups(String token, String fieldKey) throws CatalogAuthenticationException {
Expand Down Expand Up @@ -197,9 +198,14 @@ public Object getClaim(String token, String claimId, Key publicKey) throws Catal
return parseClaims(token, publicKey).getBody().get(claimId);
}

private Jws<Claims> parseClaims(String token) throws CatalogAuthenticationException {
return parseClaims(token, null);
}

private Jws<Claims> parseClaims(String token, Key publicKey) throws CatalogAuthenticationException {
Key key = publicKey != null ? publicKey : this.publicKey;
try {
return Jwts.parser().setSigningKey(publicKey).parseClaimsJws(token);
return Jwts.parser().setSigningKey(key).parseClaimsJws(token);
} catch (ExpiredJwtException e) {
logger.error("JWT Error: '{}'", e.getMessage(), e);
throw CatalogAuthenticationException.tokenExpired(token);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,30 @@ public AuthenticationResponse authenticate(String organizationId, String userId,
return new AuthenticationResponse(createToken(organizationId, userId, claims));
}

@Override
public AuthenticationResponse authenticate(String organizationId, String userId, String password, String secretKey)
throws CatalogAuthenticationException {
Map<String, Object> claims = new HashMap<>();

List<Attributes> userInfoFromLDAP = getUserInfoFromLDAP(Arrays.asList(userId), usersSearch);
if (userInfoFromLDAP.isEmpty()) {
throw new CatalogAuthenticationException("LDAP: The user id " + userId + " could not be found.");
}

String rdn = getDN(userInfoFromLDAP.get(0));
claims.put(OPENCGA_DISTINGUISHED_NAME, rdn);

// Attempt to authenticate
Hashtable<String, Object> env = getEnv(rdn, password);
try {
getDirContext(env).close();
} catch (NamingException e) {
throw wrapException(e);
}

return new AuthenticationResponse(createToken(organizationId, userId, claims, secretKey));
}

@Override
public List<User> getUsersFromRemoteGroup(String group) throws CatalogException {
List<String> usersFromLDAP = getUsersFromLDAPGroup(group, groupsSearch);
Expand Down Expand Up @@ -237,17 +261,17 @@ public void newPassword(String organizationId, String userId, String newPassword
}

@Override
public String createToken(String organizationId, String userId, Map<String, Object> claims, long expiration)
public String createToken(String organizationId, String userId, Map<String, Object> claims, long expiration, Key secretKey)
throws CatalogAuthenticationException {
List<JwtPayload.FederationJwtPayload> federations = getFederations(organizationId, userId);
return jwtManager.createJWTToken(organizationId, AuthenticationType.LDAP, userId, claims, federations, expiration);
return jwtManager.createJWTToken(organizationId, AuthenticationType.LDAP, userId, claims, federations, secretKey, expiration);
}

@Override
public String createNonExpiringToken(String organizationId, String userId, Map<String, Object> claims)
throws CatalogAuthenticationException {
List<JwtPayload.FederationJwtPayload> federations = getFederations(organizationId, userId);
return jwtManager.createJWTToken(organizationId, AuthenticationType.LDAP, userId, claims, federations, 0L);
return jwtManager.createJWTToken(organizationId, AuthenticationType.LDAP, userId, claims, federations, null, 0L);
}

/* Private methods */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,12 @@ public AuthenticationResponse authenticate(String organizationId, String userId,
throw new NotImplementedException("Authentication should be done through SSO");
}

@Override
public AuthenticationResponse authenticate(String organizationId, String userId, String password, String secretKey)
throws CatalogAuthenticationException {
throw new NotImplementedException("Authentication should be done through SSO");
}

@Override
public List<User> getUsersFromRemoteGroup(String group) throws CatalogException {
throw new NotImplementedException("Operation not implemented");
Expand Down Expand Up @@ -73,18 +79,19 @@ public void newPassword(String organizationId, String userId, String newPassword
}

@Override
public String createToken(String organizationId, String userId, Map<String, Object> claims, long expiration)
public String createToken(String organizationId, String userId, Map<String, Object> claims, long expiration, Key secretKey)
throws CatalogAuthenticationException {
List<JwtPayload.FederationJwtPayload> federations = getFederations(organizationId, userId);
return jwtManager.createJWTToken(organizationId, AuthenticationOrigin.AuthenticationType.SSO, userId, claims, federations,
expiration);
secretKey, expiration);
}

@Override
public String createNonExpiringToken(String organizationId, String userId, Map<String, Object> claims)
throws CatalogAuthenticationException {
List<JwtPayload.FederationJwtPayload> federations = getFederations(organizationId, userId);
return jwtManager.createJWTToken(organizationId, AuthenticationOrigin.AuthenticationType.SSO, userId, claims, federations, 0L);
return jwtManager.createJWTToken(organizationId, AuthenticationOrigin.AuthenticationType.SSO, userId, claims, federations, null,
0L);
}

@Override
Expand Down
Loading

0 comments on commit fbd759b

Please sign in to comment.