From 1f8cec8ca1028f0a7c74e9081338c45533991f4d Mon Sep 17 00:00:00 2001 From: Adrian Damian Date: Wed, 10 Jul 2024 09:50:32 -0700 Subject: [PATCH] Initial version --- .../server/web/users/UserActionFactory.java | 6 +- cadc-access-control/build.gradle | 2 +- .../nrc/cadc/ac/xml/AbstractReaderWriter.java | 13 +--- .../cadc/ac/xml/IdentityReaderWriterTest.java | 9 --- cadc-gms/build.gradle | 4 +- .../auth/StandardIdentityManager.java | 59 +++++++++++-------- 6 files changed, 41 insertions(+), 52 deletions(-) diff --git a/cadc-access-control-server/src/main/java/ca/nrc/cadc/ac/server/web/users/UserActionFactory.java b/cadc-access-control-server/src/main/java/ca/nrc/cadc/ac/server/web/users/UserActionFactory.java index e3585d7d..712921b7 100644 --- a/cadc-access-control-server/src/main/java/ca/nrc/cadc/ac/server/web/users/UserActionFactory.java +++ b/cadc-access-control-server/src/main/java/ca/nrc/cadc/ac/server/web/users/UserActionFactory.java @@ -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 @@ -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); diff --git a/cadc-access-control/build.gradle b/cadc-access-control/build.gradle index b2109943..6af2a3c5 100644 --- a/cadc-access-control/build.gradle +++ b/cadc-access-control/build.gradle @@ -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' diff --git a/cadc-access-control/src/main/java/ca/nrc/cadc/ac/xml/AbstractReaderWriter.java b/cadc-access-control/src/main/java/ca/nrc/cadc/ac/xml/AbstractReaderWriter.java index 1665779b..496d5573 100644 --- a/cadc-access-control/src/main/java/ca/nrc/cadc/ac/xml/AbstractReaderWriter.java +++ b/cadc-access-control/src/main/java/ca/nrc/cadc/ac/xml/AbstractReaderWriter.java @@ -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 @@ -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; @@ -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)); } @@ -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()); diff --git a/cadc-access-control/src/test/java/ca/nrc/cadc/ac/xml/IdentityReaderWriterTest.java b/cadc-access-control/src/test/java/ca/nrc/cadc/ac/xml/IdentityReaderWriterTest.java index 5e09999c..bc931d01 100644 --- a/cadc-access-control/src/test/java/ca/nrc/cadc/ac/xml/IdentityReaderWriterTest.java +++ b/cadc-access-control/src/test/java/ca/nrc/cadc/ac/xml/IdentityReaderWriterTest.java @@ -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; /** @@ -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 diff --git a/cadc-gms/build.gradle b/cadc-gms/build.gradle index cda03c01..500e308e 100644 --- a/cadc-gms/build.gradle +++ b/cadc-gms/build.gradle @@ -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)' diff --git a/cadc-gms/src/main/java/org/opencadc/auth/StandardIdentityManager.java b/cadc-gms/src/main/java/org/opencadc/auth/StandardIdentityManager.java index bb35aca4..968d69c8 100644 --- a/cadc-gms/src/main/java/org/opencadc/auth/StandardIdentityManager.java +++ b/cadc-gms/src/main/java/org/opencadc/auth/StandardIdentityManager.java @@ -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 @@ -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; @@ -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; @@ -125,6 +126,8 @@ public class StandardIdentityManager implements IdentityManager { private RegistryClient reg = new RegistryClient(); private final List 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(); @@ -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); } @@ -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(); @@ -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) { @@ -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? @@ -278,11 +288,12 @@ public Subject toSubject(Object owner) { @Override public Object toOwner(Subject subject) { // use NumericPrincipal aka OIDC sub for persistence - Set ps = subject.getPrincipals(NumericPrincipal.class); + Set ps = subject.getPrincipals(OpenIdPrincipal.class); 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 @@ -307,8 +318,8 @@ public String toDisplayString(Subject subject) { private void validateOidcAccessToken(Subject s) { log.debug("validateOidcAccessToken - START"); Set 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) { @@ -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 { @@ -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); @@ -372,8 +383,8 @@ private void validateOidcAccessToken(Subject s) { } } } + log.debug("validateOidcAccessToken - DONE"); } - log.debug("validateOidcAccessToken - DONE"); } private URL getUserEndpoint() {