Skip to content
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

Added support for OpenIdPrincipals with different issuers #170

Merged
merged 1 commit into from
Jul 24, 2024
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
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
******************* CANADIAN ASTRONOMY DATA CENTRE *******************
************** CENTRE CANADIEN DE DONNÉES ASTRONOMIQUES **************
*
* (c) 2014. (c) 2014.
* (c) 2024. (c) 2024.
* Government of Canada Gouvernement du Canada
* National Research Council Conseil national de recherches
* Ottawa, Canada, K1A 0R6 Ottawa, Canada, K1A 0R6
Expand Down Expand Up @@ -256,10 +256,6 @@ else if (idType.equalsIgnoreCase(IdentityType.CADC.getValue()))
{
return new NumericPrincipal(UUID.fromString(userName));
}
else if (idType.equalsIgnoreCase(IdentityType.OPENID.getValue()))
{
return new OpenIdPrincipal(userName);
}
else if (idType.equalsIgnoreCase(IdentityType.COOKIE.getValue()))
{
return new CookiePrincipal(SSOCookieManager.DEFAULT_SSO_COOKIE_NAME, userName);
Expand Down
2 changes: 1 addition & 1 deletion cadc-access-control/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ sourceCompatibility = 1.8

group = 'org.opencadc'

version = '1.1.27'
version = '1.1.29'

description = 'OpenCADC User+Group client library'
def git_url = 'https://github.com/opencadc/ac'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
******************* CANADIAN ASTRONOMY DATA CENTRE *******************
************** CENTRE CANADIEN DE DONNÉES ASTRONOMIQUES **************
*
* (c) 2019. (c) 2019.
* (c) 2024. (c) 2024.
* Government of Canada Gouvernement du Canada
* National Research Council Conseil national de recherches
* Ottawa, Canada, K1A 0R6 Ottawa, Canada, K1A 0R6
Expand Down Expand Up @@ -103,7 +103,6 @@
import ca.nrc.cadc.auth.HttpPrincipal;
import ca.nrc.cadc.auth.IdentityType;
import ca.nrc.cadc.auth.NumericPrincipal;
import ca.nrc.cadc.auth.OpenIdPrincipal;
import ca.nrc.cadc.auth.PosixPrincipal;
import ca.nrc.cadc.date.DateUtil;

Expand Down Expand Up @@ -282,11 +281,7 @@ protected final Principal getPrincipal(Element element)

String identity = element.getText();
Principal principal;
if (type.equals(IdentityType.OPENID.getValue()))
{
principal = new OpenIdPrincipal(identity);
}
else if (type.equals(IdentityType.CADC.getValue()))
if (type.equals(IdentityType.CADC.getValue()))
{
principal = new NumericPrincipal(UUID.fromString(identity));
}
Expand Down Expand Up @@ -784,10 +779,6 @@ else if ((identity instanceof NumericPrincipal))
{
identityElement.setAttribute(TYPE, IdentityType.CADC.getValue());
}
else if ((identity instanceof OpenIdPrincipal))
{
identityElement.setAttribute(TYPE, IdentityType.OPENID.getValue());
}
else if ((identity instanceof X500Principal))
{
identityElement.setAttribute(TYPE, IdentityType.X500.getValue());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,6 @@
import ca.nrc.cadc.ac.WriterException;
import ca.nrc.cadc.auth.HttpPrincipal;
import ca.nrc.cadc.auth.NumericPrincipal;
import ca.nrc.cadc.auth.OpenIdPrincipal;
import ca.nrc.cadc.util.PropertiesReader;

/**
Expand Down Expand Up @@ -193,14 +192,6 @@ public void testReadWrite()

assertEquals(expected, actual);

// OpenID
expected = new OpenIdPrincipal("bar");
element = getElement(expected);
assertNotNull(element);

actual = getPrincipal(element);
assertNotNull(actual);

assertEquals(expected, actual);

// HTTP
Expand Down
4 changes: 2 additions & 2 deletions cadc-gms/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,13 @@ sourceCompatibility = 1.8

group = 'org.opencadc'

version = '1.0.12'
version = '1.0.13'

description = 'OpenCADC GMS API library'
def git_url = 'https://github.com/opencadc/ac'

dependencies {
compile 'org.opencadc:cadc-util:[1.10,2.0)'
compile 'org.opencadc:cadc-util:[1.11.3,2.0)'
compile 'org.opencadc:cadc-registry:[1.6,2.0)'
compile 'org.opencadc:cadc-cdp:[1.3,2.0)'

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
******************* CANADIAN ASTRONOMY DATA CENTRE *******************
************** CENTRE CANADIEN DE DONNÉES ASTRONOMIQUES **************
*
* (c) 2023. (c) 2023.
* (c) 2024. (c) 2024.
* Government of Canada Gouvernement du Canada
* National Research Council Conseil national de recherches
* Ottawa, Canada, K1A 0R6 Ottawa, Canada, K1A 0R6
Expand Down Expand Up @@ -74,7 +74,7 @@
import ca.nrc.cadc.auth.HttpPrincipal;
import ca.nrc.cadc.auth.IdentityManager;
import ca.nrc.cadc.auth.NotAuthenticatedException;
import ca.nrc.cadc.auth.NumericPrincipal;
import ca.nrc.cadc.auth.OpenIdPrincipal;
import ca.nrc.cadc.auth.PosixPrincipal;
import ca.nrc.cadc.net.HttpGet;
import ca.nrc.cadc.reg.Standards;
Expand All @@ -90,6 +90,7 @@
import java.security.PrivilegedExceptionAction;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;
Expand Down Expand Up @@ -125,6 +126,8 @@ public class StandardIdentityManager implements IdentityManager {
private RegistryClient reg = new RegistryClient();
private final List<String> oidcDomains = new ArrayList<>();
private URI oidcScope;

private static final String OID_OWNER_DELIM = " "; // delimiter between issuer and openID that form the owner str

public StandardIdentityManager() {
LocalAuthority loc = new LocalAuthority();
Expand All @@ -133,13 +136,13 @@ public StandardIdentityManager() {
try {
URL u = oidcIssuer.toURL();
oidcDomains.add(u.getHost());

// add known and assume trusted A&A services
String host = getProviderHostname(loc, Standards.GMS_SEARCH_10);
if (host != null) {
oidcDomains.add(host);
}

} catch (MalformedURLException ex) {
throw new InvalidConfigException("found " + key + " = " + oidcIssuer + " - expected valid URL", ex);
}
Expand Down Expand Up @@ -178,7 +181,7 @@ public Subject validate(Subject subject) throws NotAuthenticatedException {

@Override
public Subject augment(Subject subject) {
// oidc tokens: validate gets HttpPrincipal and NumericPrincipal
// oidc tokens: validate gets HttpPrincipal and OpenIdPrincipal
// cadc signed cookies/tokens: validate gets all identities
boolean hasPP = !subject.getPrincipals(PosixPrincipal.class).isEmpty();
boolean hasHP = !subject.getPrincipals(HttpPrincipal.class).isEmpty();
Expand Down Expand Up @@ -244,18 +247,25 @@ public Subject augment(Subject subject) {
@Override
public Subject toSubject(Object owner) {
Subject ret = new Subject();
OpenIdPrincipal p = null;
if (owner != null) {
UUID uuid = null;
if (owner instanceof UUID) {
uuid = (UUID) owner;
} else if (owner instanceof String) {
String sub = (String) owner;
uuid = UUID.fromString(sub);
if (owner instanceof String) {
String[] openIDComponents = ((String)owner).split(OID_OWNER_DELIM); // "issuer openID"
if (openIDComponents.length != 2) {
throw new RuntimeException("unexpected owner format: " + owner.getClass().getName() + " value: " + owner);
}
URL issuer = null;
try {
issuer = new URL(openIDComponents[0]);
} catch (MalformedURLException e) {
throw new RuntimeException(
"incorrect issuer format for owner: " + owner.getClass().getName() + " value: " + owner);
}
p = new OpenIdPrincipal(issuer, openIDComponents[1]);
} else {
throw new RuntimeException("unexpected owner type: " + owner.getClass().getName() + " value: " + owner);
}
NumericPrincipal p = new NumericPrincipal(uuid);


// effectively augment by using the current subject as a "cache" of known identities
Subject s = AuthenticationUtil.getCurrentSubject();
if (s != null) {
Expand All @@ -267,7 +277,7 @@ public Subject toSubject(Object owner) {
}
}
}

ret.getPrincipals().add(p);
// this is sufficient for some purposes, but not for output using toDisplayString (eg vospace node owner)
// TODO: use PosixMapperClient.augment() to try to add a PosixPrincipal and infer an HttpPrincipal?
Expand All @@ -278,11 +288,12 @@ public Subject toSubject(Object owner) {
@Override
public Object toOwner(Subject subject) {
// use NumericPrincipal aka OIDC sub for persistence
Set<NumericPrincipal> ps = subject.getPrincipals(NumericPrincipal.class);
Set<OpenIdPrincipal> ps = subject.getPrincipals(OpenIdPrincipal.class);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

comment above is now wrong; no comment needed since code is now 100% clear

if (ps.isEmpty()) {
return null;
}
return ps.iterator().next().getUUID().toString();
OpenIdPrincipal openIdPrincipal = ps.iterator().next();
return openIdPrincipal.getIssuer().toString() + OID_OWNER_DELIM + openIdPrincipal.getName();
}

@Override
Expand All @@ -307,8 +318,8 @@ public String toDisplayString(Subject subject) {
private void validateOidcAccessToken(Subject s) {
log.debug("validateOidcAccessToken - START");
Set<AuthorizationTokenPrincipal> rawTokens = s.getPrincipals(AuthorizationTokenPrincipal.class);
log.debug("token issuer: " + oidcIssuer + " rawTokens: " + rawTokens.size());

log.debug("token issuer: " + oidcIssuer + " rawTokens: " + rawTokens.size());
if (oidcIssuer != null && !rawTokens.isEmpty()) {
URL u = getUserEndpoint();
for (AuthorizationTokenPrincipal raw : rawTokens) {
Expand All @@ -325,12 +336,12 @@ private void validateOidcAccessToken(Subject s) {
credentials = tval[1];
} else {
throw new NotAuthenticatedException(challengeType, NotAuthenticatedException.AuthError.INVALID_REQUEST,
"invalid authorization");
"invalid authorization");
}
} // else: some other challenge
} // else: some other challenge
log.debug("challenge type: " + challengeType);
log.debug("credentials: " + credentials);

// validate
if (challengeType != null && credentials != null) {
try {
Expand All @@ -345,11 +356,11 @@ private void validateOidcAccessToken(Subject s) {
String username = json.getString("preferred_username");
// TODO: register an X509 DN with IAM and see if I can get it back here

NumericPrincipal np = new NumericPrincipal(UUID.fromString(sub));
OpenIdPrincipal oip = new OpenIdPrincipal(oidcIssuer.toURL(), sub);
HttpPrincipal hp = new HttpPrincipal(username);

s.getPrincipals().remove(raw);
s.getPrincipals().add(np);
s.getPrincipals().add(oip);
s.getPrincipals().add(hp);

AuthorizationToken authToken = new AuthorizationToken(challengeType, credentials, oidcDomains, oidcScope);
Expand All @@ -372,8 +383,8 @@ private void validateOidcAccessToken(Subject s) {
}
}
}
log.debug("validateOidcAccessToken - DONE");
}
log.debug("validateOidcAccessToken - DONE");
}

private URL getUserEndpoint() {
Expand Down
Loading