From 648cc5a4d988e050a64a1a25dbbdcf5fc2511819 Mon Sep 17 00:00:00 2001 From: Adrian Damian Date: Thu, 12 Jun 2025 16:36:48 -0700 Subject: [PATCH 1/4] Changes required to support JWT tokens --- cadc-util/build.gradle | 2 +- .../ca/nrc/cadc/auth/AuthenticationUtil.java | 5 ++++- .../java/ca/nrc/cadc/auth/SignedToken.java | 19 +++++++++++++++++++ .../java/ca/nrc/cadc/auth/TokenValidator.java | 9 ++++++--- .../ca/nrc/cadc/auth/TokenValidatorTest.java | 17 ++++++++++++++--- 5 files changed, 44 insertions(+), 8 deletions(-) diff --git a/cadc-util/build.gradle b/cadc-util/build.gradle index 4a2a4f20..4972154b 100644 --- a/cadc-util/build.gradle +++ b/cadc-util/build.gradle @@ -15,7 +15,7 @@ sourceCompatibility = 1.8 group = 'org.opencadc' -version = '1.12.4' +version = '1.12.5' description = 'OpenCADC core utility library' def git_url = 'https://github.com/opencadc/core' diff --git a/cadc-util/src/main/java/ca/nrc/cadc/auth/AuthenticationUtil.java b/cadc-util/src/main/java/ca/nrc/cadc/auth/AuthenticationUtil.java index dcb95188..89be397a 100644 --- a/cadc-util/src/main/java/ca/nrc/cadc/auth/AuthenticationUtil.java +++ b/cadc-util/src/main/java/ca/nrc/cadc/auth/AuthenticationUtil.java @@ -112,7 +112,7 @@ public class AuthenticationUtil { // HTTP/1.1 Authorization header as defined by RFC 7235 public static final String AUTHORIZATION_HEADER = "Authorization"; - + // HTTP/1.1 WWW-Authenticate header public static final String AUTHENTICATE_HEADER = "WWW-Authenticate"; @@ -776,6 +776,9 @@ public static String getPrincipalType(Principal userID) { if (userID instanceof X500Principal) { return IdentityType.X500.getValue().toLowerCase(); } + if (userID instanceof OpenIdPrincipal) { + return ((OpenIdPrincipal)userID).getIssuer().toExternalForm(); + } if (userID instanceof HttpPrincipal) { return IdentityType.USERNAME.getValue().toLowerCase(); } diff --git a/cadc-util/src/main/java/ca/nrc/cadc/auth/SignedToken.java b/cadc-util/src/main/java/ca/nrc/cadc/auth/SignedToken.java index ad484743..fed4d59d 100644 --- a/cadc-util/src/main/java/ca/nrc/cadc/auth/SignedToken.java +++ b/cadc-util/src/main/java/ca/nrc/cadc/auth/SignedToken.java @@ -248,6 +248,25 @@ private static StringBuilder getContent(SignedToken token) { return sb; } + /** + * Checks whether a token is a CADC access token or not + * @param text Token to check + * @return true if the token is a CADC access token, false otherwise + */ + public static boolean isSignedToken(String text) { + if (text.startsWith(SignedToken.EXPIRY_LABEL)) { + return true; + } + // otherwise assume it is a base64 encoded token + try { + String val = new String(Base64.decode(text)); + return val.contains(VALUE_DELIM); + } catch (Exception e) { + // not a base64 encoded string + return false; + } + } + /** * Builds a DelegationToken from a text string * diff --git a/cadc-util/src/main/java/ca/nrc/cadc/auth/TokenValidator.java b/cadc-util/src/main/java/ca/nrc/cadc/auth/TokenValidator.java index f04e53b5..933e5249 100644 --- a/cadc-util/src/main/java/ca/nrc/cadc/auth/TokenValidator.java +++ b/cadc-util/src/main/java/ca/nrc/cadc/auth/TokenValidator.java @@ -96,7 +96,7 @@ public class TokenValidator { * @throws AccessControlException */ public static Subject validateTokens(Subject subject) throws NotAuthenticatedException { - + // cookies Set cookiePrincipals = subject.getPrincipals(CookiePrincipal.class); log.debug("validateTokens: found " + cookiePrincipals.size() + " cookie principals"); @@ -116,7 +116,7 @@ public static Subject validateTokens(Subject subject) throws NotAuthenticatedExc } } } - + // tokens Set tokenPrincipals = subject.getPrincipals(AuthorizationTokenPrincipal.class); log.debug("validateTokens: found " + tokenPrincipals.size() + " token principals"); @@ -149,11 +149,14 @@ public static Subject validateTokens(Subject subject) throws NotAuthenticatedExc log.debug("credentials: " + credentials); try { + if (!SignedToken.isSignedToken(credentials)) { + continue; // could be a JWT for downstream processing + } SignedToken validatedToken = SignedToken.parse(credentials); subject.getPrincipals().addAll(validatedToken.getIdentityPrincipals()); AuthorizationToken authToken = new AuthorizationToken( - challengeType, credentials, validatedToken.getDomains(), validatedToken.getScope()); + challengeType, credentials, validatedToken.getDomains(), validatedToken.getScope()); log.debug("Adding token credential to subject, removing token principal"); subject.getPublicCredentials().add(authToken); diff --git a/cadc-util/src/test/java/ca/nrc/cadc/auth/TokenValidatorTest.java b/cadc-util/src/test/java/ca/nrc/cadc/auth/TokenValidatorTest.java index 45e62ac2..ace682a9 100644 --- a/cadc-util/src/test/java/ca/nrc/cadc/auth/TokenValidatorTest.java +++ b/cadc-util/src/test/java/ca/nrc/cadc/auth/TokenValidatorTest.java @@ -165,10 +165,14 @@ public void testValidateTokens() { } catch (NotAuthenticatedException ex) { Assert.assertTrue("exception message", ex.getMessage().contains("unsupported challenge type: ivoa")); } - - // invalid bearer token + + + // invalid bearer token (expired + Date expired = new Date(new Date().getTime() - (48 * 3600 * 1000)); subject = new Subject(); - authPrincipal = new AuthorizationTokenPrincipal(AuthenticationUtil.AUTHORIZATION_HEADER, "Bearer tampered"); + token = new SignedToken(new HttpPrincipal("user"), URI.create("the:scope"), expired, domains); + value = SignedToken.format(token); + authPrincipal = new AuthorizationTokenPrincipal(AuthenticationUtil.AUTHORIZATION_HEADER, "Bearer " + value); subject.getPrincipals().add(authPrincipal); try { subject = TokenValidator.validateTokens(subject); @@ -178,6 +182,13 @@ public void testValidateTokens() { Assert.assertEquals("invalid_token", e.getAuthError().getValue()); } + // invalid bearer CADC access token - ignored + subject = new Subject(); + authPrincipal = new AuthorizationTokenPrincipal(AuthenticationUtil.AUTHORIZATION_HEADER, "Bearer tampered"); + subject.getPrincipals().add(authPrincipal); + subject = TokenValidator.validateTokens(subject); + Assert.assertTrue("invalid bearer token ignored", subject.getPrincipals().contains(authPrincipal)); + // unsupported challenge type subject = new Subject(); token = new SignedToken(new HttpPrincipal("user"), null, expiry, domains); From 9780ae32b4c85b3b605391a27fe0961db34f2d8f Mon Sep 17 00:00:00 2001 From: Adrian Damian Date: Thu, 17 Jul 2025 11:20:14 -0700 Subject: [PATCH 2/4] Re-wored after code review --- cadc-auth-restlet/README.md | 3 - cadc-auth-restlet/build.gradle | 27 -- .../restlet/RestletPrincipalExtractor.java | 265 -------------- .../RestletPrincipalExtractorTest.java | 342 ------------------ cadc-util/build.gradle | 2 +- .../ca/nrc/cadc/auth/AuthenticationUtil.java | 8 - .../cadc/auth/ServletPrincipalExtractor.java | 7 - .../java/ca/nrc/cadc/auth/SignedToken.java | 10 +- .../java/ca/nrc/cadc/auth/TokenValidator.java | 44 +-- .../nrc/cadc/auth/AuthenticationUtilTest.java | 10 - .../auth/ServletPrincipalExtractorTest.java | 4 - .../ca/nrc/cadc/auth/TokenValidatorTest.java | 18 +- 12 files changed, 23 insertions(+), 717 deletions(-) delete mode 100644 cadc-auth-restlet/README.md delete mode 100644 cadc-auth-restlet/build.gradle delete mode 100644 cadc-auth-restlet/src/main/java/ca/nrc/cadc/auth/restlet/RestletPrincipalExtractor.java delete mode 100644 cadc-auth-restlet/src/test/java/ca/nrc/cadc/auth/restlet/RestletPrincipalExtractorTest.java diff --git a/cadc-auth-restlet/README.md b/cadc-auth-restlet/README.md deleted file mode 100644 index 62c19d8c..00000000 --- a/cadc-auth-restlet/README.md +++ /dev/null @@ -1,3 +0,0 @@ - -auth-restlet is obsolete and not published to Maven Central - diff --git a/cadc-auth-restlet/build.gradle b/cadc-auth-restlet/build.gradle deleted file mode 100644 index 06a93c5a..00000000 --- a/cadc-auth-restlet/build.gradle +++ /dev/null @@ -1,27 +0,0 @@ -plugins { - id 'java' - id 'maven' - id 'maven-publish' - id 'com.jfrog.bintray' version '1.8.4' -} - -repositories { - jcenter() - mavenLocal() -} - -sourceCompatibility = 1.7 - -group = 'org.opencadc' - -version = '1.2.2' - -dependencies { - compile 'log4j:log4j:1.2.17' - compile 'org.restlet.jse:org.restlet:2.0.2' - - compile 'org.opencadc:cadc-util:[1.2.13,1.3)' - - testCompile 'junit:junit:4.13' - testCompile 'org.easymock:easymock:3.6' -} diff --git a/cadc-auth-restlet/src/main/java/ca/nrc/cadc/auth/restlet/RestletPrincipalExtractor.java b/cadc-auth-restlet/src/main/java/ca/nrc/cadc/auth/restlet/RestletPrincipalExtractor.java deleted file mode 100644 index 5fe2ca06..00000000 --- a/cadc-auth-restlet/src/main/java/ca/nrc/cadc/auth/restlet/RestletPrincipalExtractor.java +++ /dev/null @@ -1,265 +0,0 @@ -/* -************************************************************************ -******************* CANADIAN ASTRONOMY DATA CENTRE ******************* -************** CENTRE CANADIEN DE DONNÉES ASTRONOMIQUES ************** -* -* (c) 2018. (c) 2018. -* Government of Canada Gouvernement du Canada -* National Research Council Conseil national de recherches -* Ottawa, Canada, K1A 0R6 Ottawa, Canada, K1A 0R6 -* All rights reserved Tous droits réservés -* -* NRC disclaims any warranties, Le CNRC dénie toute garantie -* expressed, implied, or énoncée, implicite ou légale, -* statutory, of any kind with de quelque nature que ce -* respect to the software, soit, concernant le logiciel, -* including without limitation y compris sans restriction -* any warranty of merchantability toute garantie de valeur -* or fitness for a particular marchande ou de pertinence -* purpose. NRC shall not be pour un usage particulier. -* liable in any event for any Le CNRC ne pourra en aucun cas -* damages, whether direct or être tenu responsable de tout -* indirect, special or general, dommage, direct ou indirect, -* consequential or incidental, particulier ou général, -* arising from the use of the accessoire ou fortuit, résultant -* software. Neither the name de l'utilisation du logiciel. Ni -* of the National Research le nom du Conseil National de -* Council of Canada nor the Recherches du Canada ni les noms -* names of its contributors may de ses participants ne peuvent -* be used to endorse or promote être utilisés pour approuver ou -* products derived from this promouvoir les produits dérivés -* software without specific prior de ce logiciel sans autorisation -* written permission. préalable et particulière -* par écrit. -* -* This file is part of the Ce fichier fait partie du projet -* OpenCADC project. OpenCADC. -* -* OpenCADC is free software: OpenCADC est un logiciel libre ; -* you can redistribute it and/or vous pouvez le redistribuer ou le -* modify it under the terms of modifier suivant les termes de -* the GNU Affero General Public la “GNU Affero General Public -* License as published by the License” telle que publiée -* Free Software Foundation, par la Free Software Foundation -* either version 3 of the : soit la version 3 de cette -* License, or (at your option) licence, soit (à votre gré) -* any later version. toute version ultérieure. -* -* OpenCADC is distributed in the OpenCADC est distribué -* hope that it will be useful, dans l’espoir qu’il vous -* but WITHOUT ANY WARRANTY; sera utile, mais SANS AUCUNE -* without even the implied GARANTIE : sans même la garantie -* warranty of MERCHANTABILITY implicite de COMMERCIALISABILITÉ -* or FITNESS FOR A PARTICULAR ni d’ADÉQUATION À UN OBJECTIF -* PURPOSE. See the GNU Affero PARTICULIER. Consultez la Licence -* General Public License for Générale Publique GNU Affero -* more details. pour plus de détails. -* -* You should have received Vous devriez avoir reçu une -* a copy of the GNU Affero copie de la Licence Générale -* General Public License along Publique GNU Affero avec -* with OpenCADC. If not, see OpenCADC ; si ce n’est -* . pas le cas, consultez : -* . -* -* $Revision: 5 $ -* -************************************************************************ - */ - -package ca.nrc.cadc.auth.restlet; - -import ca.nrc.cadc.auth.AuthenticationUtil; -import ca.nrc.cadc.auth.DelegationToken; -import ca.nrc.cadc.auth.HttpPrincipal; -import ca.nrc.cadc.auth.InvalidDelegationTokenException; -import ca.nrc.cadc.auth.NotAuthenticatedException; -import ca.nrc.cadc.auth.PrincipalExtractor; -import ca.nrc.cadc.auth.SSLUtil; -import ca.nrc.cadc.auth.SSOCookieCredential; -import ca.nrc.cadc.auth.SSOCookieManager; -import ca.nrc.cadc.auth.X509CertificateChain; -import ca.nrc.cadc.net.NetUtil; -import ca.nrc.cadc.util.ArrayUtil; -import ca.nrc.cadc.util.StringUtil; -import java.io.IOException; -import java.security.AccessControlException; -import java.security.Principal; -import java.security.cert.X509Certificate; -import java.util.Arrays; -import java.util.Collection; -import java.util.HashSet; -import java.util.List; -import java.util.Set; -import org.apache.log4j.Logger; -import org.restlet.Request; -import org.restlet.data.Cookie; -import org.restlet.data.Form; -import org.restlet.util.Series; - -/** - * Principal Extractor implementation using a Restlet Request. - */ -public class RestletPrincipalExtractor implements PrincipalExtractor { - - private static final Logger log = Logger.getLogger(RestletPrincipalExtractor.class); - - private final Request request; - private X509CertificateChain chain; - private DelegationToken token; - - private List cookieCredentialList; - private Set cookiePrincipals = new HashSet<>(); // identities extracted from cookie - private Set principals = new HashSet<>(); - - /** - * Hidden no-arg constructor for testing. - */ - RestletPrincipalExtractor() { - this.request = null; - } - - /** - * Create this extractor from the given Restlet Request. - * - * @param req The Restlet Request. - */ - public RestletPrincipalExtractor(final Request req) { - this.request = req; - } - - private void init() { - - if (chain == null) { - final Collection requestCertificates - = (Collection) getRequest().getAttributes().get( - "org.restlet.https.clientCertificates"); - if ((requestCertificates != null) && (!requestCertificates.isEmpty())) { - this.chain = new X509CertificateChain(requestCertificates); - principals.add(this.chain.getPrincipal()); - } - } - - log.debug("Value of CERT_HEADER_ENABLE sys prop: " + System.getProperty(CERT_HEADER_ENABLE)); - if (chain == null && "true".equals(System.getProperty(CERT_HEADER_ENABLE))) { - Form allHeaders = (Form) getRequest().getAttributes().get("org.restlet.http.headers"); - String certString = allHeaders.getFirstValue(CERT_HEADER_FIELD, true); - log.debug(CERT_HEADER_FIELD + ":\n" + certString + "\n"); - if (certString != null && certString.length() > 0) { - try { - byte[] certBytes = SSLUtil.getCertificates(certString.getBytes()); - chain = new X509CertificateChain(SSLUtil.readCertificateChain(certBytes), null); - principals.add(chain.getPrincipal()); - } catch (Exception e) { - log.error("Failed to read certificate", e); - throw new AccessControlException("Failed to read certificate: " + e.getMessage()); - } - } - } - - if (token == null) { - Form headers = (Form) getRequest().getAttributes().get("org.restlet.http.headers"); - String tokenValue = headers.getFirstValue(AuthenticationUtil.AUTH_HEADER, true); - if (StringUtil.hasText(tokenValue)) { - try { - this.token = DelegationToken.parse(tokenValue, request.getResourceRef().getPath()); - } catch (InvalidDelegationTokenException ex) { - log.debug("invalid DelegationToken: " + tokenValue, ex); - throw new NotAuthenticatedException("invalid delegation token. " + ex.getMessage()); - } catch (RuntimeException ex) { - log.debug("invalid DelegationToken: " + tokenValue, ex); - throw new NotAuthenticatedException("invalid delegation token. " + ex.getMessage()); - } finally { - } - } - } - - // add HttpPrincipal - final String httpUser = getAuthenticatedUsername(); - if (StringUtil.hasText(httpUser)) // user from HTTP AUTH - { - principals.add(new HttpPrincipal(httpUser)); - } else if (token != null) // user from token - { - principals.add(token.getUser()); - } - - Series cookies = getRequest().getCookies(); - log.debug("cookie count: " + cookies.size()); - log.debug("principal count: " + principals.size()); - log.debug(principals); - if (cookies == null || (cookies.size() == 0)) { - return; - } - - for (Cookie ssoCookie : cookies) { - log.debug(ssoCookie.toString()); - - if (SSOCookieManager.DEFAULT_SSO_COOKIE_NAME.equals( - ssoCookie.getName()) - && StringUtil.hasText(ssoCookie.getValue())) { - SSOCookieManager ssoCookieManager = new SSOCookieManager(); - try { - DelegationToken cookieToken = ssoCookieManager.parse( - ssoCookie.getValue()); - - cookiePrincipals = cookieToken.getIdentityPrincipals(); - principals.addAll(cookiePrincipals); - - cookieCredentialList = ssoCookieManager.getSSOCookieCredentials(ssoCookie.getValue(), - NetUtil.getDomainName(getRequest().getResourceRef().toUrl())); - } catch (InvalidDelegationTokenException | IOException e) { - log.debug("Cannot use SSO Cookie. Reason: " + e.getMessage()); - throw new NotAuthenticatedException("invalid cookie. " + e.getMessage()); - } - } - } - } - - public X509CertificateChain getCertificateChain() { - init(); - return chain; - } - - public Set getPrincipals() { - init(); - return principals; - } - - public DelegationToken getDelegationToken() { - init(); - return token; - } - - /** - * Obtain the Username submitted with the Request. - * - * @return String username, or null if none found. - */ - protected String getAuthenticatedUsername() { - final String username; - - if (!getRequest().getClientInfo().getPrincipals().isEmpty()) { - // Put in to support Safari not injecting a Challenge Response. - // Grab the first principal's name as the username. - // update: this is *always* right and works with realms; the previous - // call to getRequest().getChallengeResponse().getIdentifier() would - // return whatever username the caller provided in a non-authenticating call - username = getRequest().getClientInfo().getPrincipals().get(0).getName(); - log.debug("username: " + username); - } else { - username = null; - } - - return username; - } - - public Request getRequest() { - return request; - } - - @Override - public List getSSOCookieCredentials() { - return cookieCredentialList; - } -} diff --git a/cadc-auth-restlet/src/test/java/ca/nrc/cadc/auth/restlet/RestletPrincipalExtractorTest.java b/cadc-auth-restlet/src/test/java/ca/nrc/cadc/auth/restlet/RestletPrincipalExtractorTest.java deleted file mode 100644 index a7ae978f..00000000 --- a/cadc-auth-restlet/src/test/java/ca/nrc/cadc/auth/restlet/RestletPrincipalExtractorTest.java +++ /dev/null @@ -1,342 +0,0 @@ -/* - ************************************************************************ - **** C A N A D I A N A S T R O N O M Y D A T A C E N T R E ***** - * - * (c) 2012. (c) 2012. - * National Research Council Conseil national de recherches - * Ottawa, Canada, K1A 0R6 Ottawa, Canada, K1A 0R6 - * All rights reserved Tous droits reserves - * - * NRC disclaims any warranties Le CNRC denie toute garantie - * expressed, implied, or statu- enoncee, implicite ou legale, - * tory, of any kind with respect de quelque nature que se soit, - * to the software, including concernant le logiciel, y com- - * without limitation any war- pris sans restriction toute - * ranty of merchantability or garantie de valeur marchande - * fitness for a particular pur- ou de pertinence pour un usage - * pose. NRC shall not be liable particulier. Le CNRC ne - * in any event for any damages, pourra en aucun cas etre tenu - * whether direct or indirect, responsable de tout dommage, - * special or general, consequen- direct ou indirect, particul- - * tial or incidental, arising ier ou general, accessoire ou - * from the use of the software. fortuit, resultant de l'utili- - * sation du logiciel. - * - * - * @author jenkinsd - * 4/20/12 - 12:49 PM - * - * - * - **** C A N A D I A N A S T R O N O M Y D A T A C E N T R E ***** - ************************************************************************ - */ - -package ca.nrc.cadc.auth.restlet; - -import ca.nrc.cadc.auth.AuthenticationUtil; -import ca.nrc.cadc.auth.DelegationToken; -import ca.nrc.cadc.auth.NotAuthenticatedException; -import java.security.Principal; -import java.security.cert.X509Certificate; -import java.util.ArrayList; -import java.util.Calendar; -import java.util.Collection; -import java.util.Date; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; -import javax.security.auth.x500.X500Principal; -import org.apache.log4j.Logger; -import static org.easymock.EasyMock.*; -import static org.junit.Assert.*; -import org.junit.Assert; -import org.junit.Test; -import org.restlet.Request; -import org.restlet.data.ClientInfo; -import org.restlet.data.Cookie; -import org.restlet.data.Form; -import org.restlet.engine.util.CookieSeries; -import org.restlet.util.Series; - -public class RestletPrincipalExtractorTest { - - private static final Logger log = Logger.getLogger(RestletPrincipalExtractorTest.class); - - private RestletPrincipalExtractor testSubject; - private final Request mockRequest = createMock(Request.class); - - @Test - public void testCaseInsensitiveDelegationToken() throws Exception { - // create an invalid token and test that RestletPrincipalExtractor finds it even when case of - // attribute is changed - setTestSubject(new RestletPrincipalExtractor() { - @Override - public Request getRequest() { - return getMockRequest(); - } - - @Override - protected String getAuthenticatedUsername() { - return null; - } - }); - - final ConcurrentMap attributes - = new ConcurrentHashMap(); - Form form = new Form(AuthenticationUtil.AUTH_HEADER + "=foo"); - attributes.put("org.restlet.http.headers", form); - expect(getMockRequest().getAttributes()).andReturn(attributes).atLeastOnce(); - - replay(getMockRequest()); - try { - DelegationToken dt = getTestSubject().getDelegationToken(); - assertTrue(false); - } catch (NotAuthenticatedException e) - { - assertEquals("Unexpected exception", "invalid delegation token. null", e.getMessage()); - } - - // repeat test with lowercase attributes - reset(getMockRequest()); - attributes.clear(); - form = new Form(AuthenticationUtil.AUTH_HEADER.toLowerCase() + "=foo"); - attributes.put("org.restlet.http.headers", form); - expect(getMockRequest().getAttributes()).andReturn(attributes).atLeastOnce(); - - replay(getMockRequest()); - try { - DelegationToken dt = getTestSubject().getDelegationToken(); - Assert.fail("reason: expected exception due to invalid token"); - } catch (NotAuthenticatedException e) - { - assertEquals("expected exception", "invalid delegation token. null", e.getMessage()); - } - } - - @Test - public void testGetDelegationToken() throws Exception { - setTestSubject(new RestletPrincipalExtractor() { - @Override - public Request getRequest() { - return getMockRequest(); - } - - @Override - protected String getAuthenticatedUsername() { - return null; - } - }); - - final Series requestCookies = new CookieSeries(); - expect(getMockRequest().getCookies()).andReturn(requestCookies).atLeastOnce(); - - final ConcurrentMap attributes - = new ConcurrentHashMap(); - Form mockHeaders = createMock(Form.class); - attributes.put("org.restlet.http.headers", mockHeaders); - expect(mockHeaders.getFirstValue(AuthenticationUtil.AUTH_HEADER, true)).andReturn(null).atLeastOnce(); - expect(getMockRequest().getAttributes()).andReturn(attributes).atLeastOnce(); - - replay(mockHeaders); - replay(getMockRequest()); - - DelegationToken dt = getTestSubject().getDelegationToken(); - System.out.println(dt); - assertNull("Should have no token", dt); - - Set ps = getTestSubject().getPrincipals(); - assertTrue("Should have no principals.", ps.isEmpty()); - - verify(getMockRequest()); - } - - @Test - public void addCookiePrincipal() throws Exception { - final Series requestCookies = new CookieSeries(); - - setTestSubject(new RestletPrincipalExtractor() { - @Override - public Request getRequest() { - return getMockRequest(); - } - }); - - final ClientInfo clientInfo = new ClientInfo(); - expect(getMockRequest().getClientInfo()).andReturn(clientInfo).atLeastOnce(); - - expect(getMockRequest().getCookies()).andReturn(requestCookies).atLeastOnce(); - - final ConcurrentMap attributes - = new ConcurrentHashMap(); - Form mockHeaders = createMock(Form.class); - attributes.put("org.restlet.http.headers", mockHeaders); - expect(mockHeaders.getFirstValue(AuthenticationUtil.AUTH_HEADER, true)).andReturn(null).atLeastOnce(); - expect(getMockRequest().getAttributes()).andReturn(attributes).atLeastOnce(); - - replay(mockHeaders); - replay(getMockRequest()); - - Set ps = getTestSubject().getPrincipals(); - - assertTrue("Should have no principals.", ps.isEmpty()); - - verify(getMockRequest()); - - // - // TEST 2 -- can't test this without full setup of keys to generate and validate - /* - reset(mockHeaders); - reset(getMockRequest()); - - String sessionID = new SSOCookieManager().generate(new HttpPrincipal("foo")); - requestCookies.add("CADC_SSO", sessionID); - - expect(getMockRequest().getClientInfo()).andReturn(clientInfo).atLeastOnce(); - - expect(getMockRequest().getCookies()).andReturn(requestCookies).atLeastOnce(); - - expect(mockHeaders.getFirstValue(AuthenticationUtil.AUTH_HEADER)).andReturn(null).atLeastOnce(); - - expect(getMockRequest().getAttributes()).andReturn(attributes).atLeastOnce(); - - replay(mockHeaders); - replay(getMockRequest()); - - ps = getTestSubject().getPrincipals(); - - assertEquals("Should have one principal.", 1, ps.size()); - CookiePrincipal cp = (CookiePrincipal) ps.iterator().next(); - assertEquals(sessionID, cp.getSessionId()); - - - verify(getMockRequest()); - */ - } - - @Test - public void addHTTPPrincipal() throws Exception { - - setTestSubject(new RestletPrincipalExtractor() { - @Override - public Request getRequest() { - return getMockRequest(); - } - - @Override - protected String getAuthenticatedUsername() { - return null; - } - }); - - final Series requestCookies = new CookieSeries(); - expect(getMockRequest().getCookies()).andReturn(requestCookies).atLeastOnce(); - - final ConcurrentMap attributes - = new ConcurrentHashMap(); - Form mockHeaders = createMock(Form.class); - attributes.put("org.restlet.http.headers", mockHeaders); - expect(mockHeaders.getFirstValue(AuthenticationUtil.AUTH_HEADER, true)).andReturn(null).atLeastOnce(); - expect(getMockRequest().getAttributes()).andReturn(attributes).atLeastOnce(); - - replay(mockHeaders); - replay(getMockRequest()); - - Set ps = getTestSubject().getPrincipals(); - - assertTrue("Should have no principals.", ps.isEmpty()); - - verify(getMockRequest()); - } - - @Test - public void addX500Principal() throws Exception { - setTestSubject(new RestletPrincipalExtractor() { - @Override - public Request getRequest() { - return getMockRequest(); - } - }); - - final ClientInfo clientInfo = new ClientInfo(); - expect(getMockRequest().getClientInfo()).andReturn(clientInfo).atLeastOnce(); - - final ConcurrentMap attributes - = new ConcurrentHashMap(); - Form mockHeaders = createMock(Form.class); - attributes.put("org.restlet.http.headers", mockHeaders); - expect(mockHeaders.getFirstValue(AuthenticationUtil.AUTH_HEADER, true)).andReturn(null).atLeastOnce(); - expect(getMockRequest().getAttributes()).andReturn(attributes).atLeastOnce(); - - final Series requestCookies = new CookieSeries(); - expect(getMockRequest().getCookies()).andReturn(requestCookies).atLeastOnce(); - - replay(mockHeaders); - replay(getMockRequest()); - - Set ps = getTestSubject().getPrincipals(); - - assertTrue("Should have no principals.", ps.isEmpty()); - - verify(getMockRequest()); - - // - // TEST 2 - reset(getMockRequest()); - - expect(getMockRequest().getClientInfo()).andReturn(clientInfo).atLeastOnce(); - - expect(getMockRequest().getCookies()).andReturn(requestCookies).atLeastOnce(); - - mockHeaders = createMock(Form.class); - attributes.put("org.restlet.http.headers", mockHeaders); - expect(mockHeaders.getFirstValue(AuthenticationUtil.AUTH_HEADER, true)).andReturn(null).atLeastOnce(); - - final Calendar notAfterCal = Calendar.getInstance(); - notAfterCal.set(1977, Calendar.NOVEMBER, 25, 3, 21, 0); - notAfterCal.set(Calendar.MILLISECOND, 0); - - final X500Principal subjectX500Principal - = new X500Principal("CN=CN1,O=O1"); - final X500Principal issuerX500Principal - = new X500Principal("CN=CN2,O=O2"); - final Date notAfterDate = notAfterCal.getTime(); - final X509Certificate mockCertificate - = createMock(X509Certificate.class); - - final Collection certificates1 - = new ArrayList(); - - certificates1.add(mockCertificate); - - attributes.put("org.restlet.https.clientCertificates", certificates1); - expect(getMockRequest().getAttributes()).andReturn(attributes).atLeastOnce(); - - expect(mockCertificate.getNotAfter()).andReturn(notAfterDate).once(); - expect(mockCertificate.getSubjectX500Principal()). - andReturn(subjectX500Principal).once(); - expect(mockCertificate.getIssuerX500Principal()).andReturn( - issuerX500Principal).once(); - - replay(mockHeaders); - replay(getMockRequest(), mockCertificate); - - ps = getTestSubject().getPrincipals(); - - assertEquals("Should have one HTTP principal.", 1, ps.size()); - - verify(getMockRequest(), mockCertificate); - } - - protected RestletPrincipalExtractor getTestSubject() { - return testSubject; - } - - protected void setTestSubject(final RestletPrincipalExtractor testSubject) { - this.testSubject = testSubject; - } - - public Request getMockRequest() { - return mockRequest; - } -} diff --git a/cadc-util/build.gradle b/cadc-util/build.gradle index fab5eef4..67b15a62 100644 --- a/cadc-util/build.gradle +++ b/cadc-util/build.gradle @@ -15,7 +15,7 @@ sourceCompatibility = 1.8 group = 'org.opencadc' -version = '1.12.7' +version = '1.12.8' description = 'OpenCADC core utility library' def git_url = 'https://github.com/opencadc/core' diff --git a/cadc-util/src/main/java/ca/nrc/cadc/auth/AuthenticationUtil.java b/cadc-util/src/main/java/ca/nrc/cadc/auth/AuthenticationUtil.java index 89be397a..bc882982 100644 --- a/cadc-util/src/main/java/ca/nrc/cadc/auth/AuthenticationUtil.java +++ b/cadc-util/src/main/java/ca/nrc/cadc/auth/AuthenticationUtil.java @@ -107,9 +107,6 @@ */ public class AuthenticationUtil { - @Deprecated // Should be using standard Authorization header - public static final String AUTH_HEADER = "X-CADC-DelegationToken"; - // HTTP/1.1 Authorization header as defined by RFC 7235 public static final String AUTHORIZATION_HEADER = "Authorization"; @@ -127,8 +124,6 @@ public class AuthenticationUtil { public static final String CHALLENGE_TYPE_IVOA_BEARER = "ivoa_bearer"; public static final String CHALLENGE_TYPE_IVOA_X509 = "ivoa_x509"; public static final String CHALLENGE_TYPE_IVOA_COOKIE = "ivoa_cookie"; - @Deprecated - public static final String TOKEN_TYPE_CADC = AUTH_HEADER; // Mandatory support list of RDN descriptors according to RFC 4512. private static final String[] ORDERED_RDN_KEYS = new String[] { "DC", "CN", "OU", "O", "STREET", "L", "ST", "C", "UID" }; @@ -776,9 +771,6 @@ public static String getPrincipalType(Principal userID) { if (userID instanceof X500Principal) { return IdentityType.X500.getValue().toLowerCase(); } - if (userID instanceof OpenIdPrincipal) { - return ((OpenIdPrincipal)userID).getIssuer().toExternalForm(); - } if (userID instanceof HttpPrincipal) { return IdentityType.USERNAME.getValue().toLowerCase(); } diff --git a/cadc-util/src/main/java/ca/nrc/cadc/auth/ServletPrincipalExtractor.java b/cadc-util/src/main/java/ca/nrc/cadc/auth/ServletPrincipalExtractor.java index 35c1f6b6..f0747a0a 100644 --- a/cadc-util/src/main/java/ca/nrc/cadc/auth/ServletPrincipalExtractor.java +++ b/cadc-util/src/main/java/ca/nrc/cadc/auth/ServletPrincipalExtractor.java @@ -136,13 +136,6 @@ public ServletPrincipalExtractor(final HttpServletRequest req) { } } - // custom header (deprecated) - String cadcTokenHeader = request.getHeader(AuthenticationUtil.AUTH_HEADER); - if (cadcTokenHeader != null) { - AuthorizationTokenPrincipal principal = new AuthorizationTokenPrincipal(AuthenticationUtil.AUTH_HEADER, cadcTokenHeader); - principals.add(principal); - } - // authorization header Enumeration authTokens = request.getHeaders(AuthenticationUtil.AUTHORIZATION_HEADER); while (authTokens.hasMoreElements()) { diff --git a/cadc-util/src/main/java/ca/nrc/cadc/auth/SignedToken.java b/cadc-util/src/main/java/ca/nrc/cadc/auth/SignedToken.java index fed4d59d..d8181f37 100644 --- a/cadc-util/src/main/java/ca/nrc/cadc/auth/SignedToken.java +++ b/cadc-util/src/main/java/ca/nrc/cadc/auth/SignedToken.java @@ -249,19 +249,15 @@ private static StringBuilder getContent(SignedToken token) { } /** - * Checks whether a token is a CADC access token or not + * Checks whether a token is a signed token or not. * @param text Token to check * @return true if the token is a CADC access token, false otherwise */ public static boolean isSignedToken(String text) { - if (text.startsWith(SignedToken.EXPIRY_LABEL)) { - return true; - } - // otherwise assume it is a base64 encoded token try { - String val = new String(Base64.decode(text)); + String val = Base64.decodeString(text); return val.contains(VALUE_DELIM); - } catch (Exception e) { + } catch (IllegalArgumentException ignore) { // not a base64 encoded string return false; } diff --git a/cadc-util/src/main/java/ca/nrc/cadc/auth/TokenValidator.java b/cadc-util/src/main/java/ca/nrc/cadc/auth/TokenValidator.java index 933e5249..dbcd727c 100644 --- a/cadc-util/src/main/java/ca/nrc/cadc/auth/TokenValidator.java +++ b/cadc-util/src/main/java/ca/nrc/cadc/auth/TokenValidator.java @@ -125,44 +125,32 @@ public static Subject validateTokens(Subject subject) throws NotAuthenticatedExc log.debug("header value: " + p.getHeaderValue()); String credentials = null; String challengeType = null; - if (AuthenticationUtil.TOKEN_TYPE_CADC.equals(p.getHeaderKey())) { - challengeType = AuthenticationUtil.TOKEN_TYPE_CADC; - credentials = p.getHeaderValue().trim(); - } else if (AuthenticationUtil.AUTHORIZATION_HEADER.equals(p.getHeaderKey())) { + if (AuthenticationUtil.AUTHORIZATION_HEADER.equals(p.getHeaderKey())) { // parse the token into challenge type and credentials. int spaceIndex = p.getHeaderValue().indexOf(" "); if (spaceIndex == -1) { throw new NotAuthenticatedException(challengeType, AuthError.INVALID_REQUEST, - "missing authorization challenge"); + "missing authorization challenge"); } challengeType = p.getHeaderValue().substring(0, spaceIndex).trim(); if (AuthenticationUtil.CHALLENGE_TYPE_BEARER.equalsIgnoreCase(challengeType)) { credentials = p.getHeaderValue().substring(spaceIndex + 1).trim(); - } - // else: ignore - // throw new NotAuthenticatedException(challengeType, AuthError.INVALID_REQUEST, - // "unsupported challenge type: " + challengeType); - //} - } - if (challengeType != null && credentials != null) { - log.debug("challenge type: " + challengeType); - log.debug("credentials: " + credentials); + try { + if (SignedToken.isSignedToken(credentials)) { + SignedToken validatedToken = SignedToken.parse(credentials); + subject.getPrincipals().addAll(validatedToken.getIdentityPrincipals()); - try { - if (!SignedToken.isSignedToken(credentials)) { - continue; // could be a JWT for downstream processing - } - SignedToken validatedToken = SignedToken.parse(credentials); - subject.getPrincipals().addAll(validatedToken.getIdentityPrincipals()); + AuthorizationToken authToken = new AuthorizationToken( + challengeType, credentials, validatedToken.getDomains(), validatedToken.getScope()); - AuthorizationToken authToken = new AuthorizationToken( - challengeType, credentials, validatedToken.getDomains(), validatedToken.getScope()); - - log.debug("Adding token credential to subject, removing token principal"); - subject.getPublicCredentials().add(authToken); - subject.getPrincipals().remove(p); - } catch (Exception ex) { - throw new NotAuthenticatedException(challengeType, AuthError.INVALID_TOKEN, ex.getMessage(), ex); + log.debug("Adding token credential to subject, removing token principal"); + subject.getPublicCredentials().add(authToken); + subject.getPrincipals().remove(p); + } // else: other kind of bearer token: leave AuthorizationTokenPrincipal for additional + // processing + } catch (Exception ex) { + throw new NotAuthenticatedException(challengeType, AuthError.INVALID_TOKEN, ex.getMessage(), ex); + } } } // ignore other challenge types diff --git a/cadc-util/src/test/java/ca/nrc/cadc/auth/AuthenticationUtilTest.java b/cadc-util/src/test/java/ca/nrc/cadc/auth/AuthenticationUtilTest.java index e40f4073..814fcc51 100755 --- a/cadc-util/src/test/java/ca/nrc/cadc/auth/AuthenticationUtilTest.java +++ b/cadc-util/src/test/java/ca/nrc/cadc/auth/AuthenticationUtilTest.java @@ -80,24 +80,19 @@ import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; -import ca.nrc.cadc.util.FileUtil; import ca.nrc.cadc.util.Log4jInit; -import ca.nrc.cadc.util.RsaSignatureGenerator; -import java.io.File; import java.net.InetAddress; import java.net.PasswordAuthentication; import java.security.Principal; import java.security.PrivateKey; import java.security.PrivilegedAction; import java.security.cert.X509Certificate; -import java.util.Arrays; import java.util.Calendar; import java.util.Collection; import java.util.Collections; import java.util.Date; import java.util.HashSet; -import java.util.List; import java.util.Map; import java.util.Set; @@ -472,7 +467,6 @@ public void testGetSubjectFromHttpServletRequest_Anon() expect(mockRequest.getRemoteUser()).andReturn(null).atLeastOnce(); expect(mockRequest.getCookies()).andReturn(null).atLeastOnce(); - expect(mockRequest.getHeader(AuthenticationUtil.AUTH_HEADER)).andReturn(null).atLeastOnce(); expect(mockRequest.getHeaders("Authorization")).andReturn(Collections.emptyEnumeration()); expect(mockRequest.getAttribute( "javax.servlet.request.X509Certificate")).andReturn(null).atLeastOnce(); @@ -513,7 +507,6 @@ public void testGetSubjectFromHttpServletRequest_XClientCertificateEnabled() expect(mockRequest.getRemoteUser()).andReturn(null).atLeastOnce(); expect(mockRequest.getCookies()).andReturn(null).atLeastOnce(); - expect(mockRequest.getHeader(AuthenticationUtil.AUTH_HEADER)).andReturn(null).atLeastOnce(); expect(mockRequest.getHeaders("Authorization")).andReturn(Collections.emptyEnumeration()); expect(mockRequest.getAttribute( "javax.servlet.request.X509Certificate")).andReturn(null).atLeastOnce(); @@ -553,7 +546,6 @@ public void testGetSubjectFromHttpServletRequest_HttpPrincipal() expect(mockRequest.getRemoteUser()).andReturn("foo").atLeastOnce(); expect(mockRequest.getCookies()).andReturn(null).atLeastOnce(); - expect(mockRequest.getHeader(AuthenticationUtil.AUTH_HEADER)).andReturn(null).atLeastOnce(); expect(mockRequest.getHeaders("Authorization")).andReturn(Collections.emptyEnumeration()); expect(mockRequest.getAttribute( "javax.servlet.request.X509Certificate")).andReturn(null).atLeastOnce(); @@ -669,7 +661,6 @@ public void testGetSubjectFromHttpServletRequest_X500Principal() expect(mockRequest.getRemoteUser()).andReturn(null).atLeastOnce(); expect(mockRequest.getCookies()).andReturn(null).atLeastOnce(); - expect(mockRequest.getHeader(AuthenticationUtil.AUTH_HEADER)).andReturn(null).atLeastOnce(); expect(mockRequest.getHeader("Authorization")).andReturn(null); expect(mockRequest.getAttribute( "javax.servlet.request.X509Certificate")).andReturn(ca).atLeastOnce(); @@ -755,7 +746,6 @@ public void testGetSubjectFromHttpServletRequest_CookiePrincipal() throws Except expect(mockRequest.getRemoteUser()).andReturn(null).atLeastOnce(); expect(mockRequest.getCookies()).andReturn(cookies).atLeastOnce(); - expect(mockRequest.getHeader(AuthenticationUtil.AUTH_HEADER)).andReturn(null).atLeastOnce(); expect(mockRequest.getHeader("Authorization")).andReturn(null); expect(mockRequest.getAttribute( "javax.servlet.request.X509Certificate")).andReturn(null).atLeastOnce(); diff --git a/cadc-util/src/test/java/ca/nrc/cadc/auth/ServletPrincipalExtractorTest.java b/cadc-util/src/test/java/ca/nrc/cadc/auth/ServletPrincipalExtractorTest.java index 0852a3e6..e1e5fef7 100644 --- a/cadc-util/src/test/java/ca/nrc/cadc/auth/ServletPrincipalExtractorTest.java +++ b/cadc-util/src/test/java/ca/nrc/cadc/auth/ServletPrincipalExtractorTest.java @@ -42,7 +42,6 @@ import ca.nrc.cadc.util.Log4jInit; import ca.nrc.cadc.util.PropertiesReader; -import ca.nrc.cadc.util.RSASignatureGeneratorValidatorTest; import ca.nrc.cadc.util.RsaSignatureGenerator; import java.io.File; @@ -54,9 +53,7 @@ import org.apache.log4j.Level; import org.apache.log4j.Logger; -import org.easymock.EasyMock; import org.junit.After; -import org.junit.Assert; import org.junit.Before; import org.junit.Test; @@ -106,7 +103,6 @@ public void testCookie() throws Exception expect(request.getAttribute( ServletPrincipalExtractor.CERT_REQUEST_ATTRIBUTE)).andReturn(null); - expect(request.getHeader(AuthenticationUtil.AUTH_HEADER)).andReturn(null); expect(request.getHeaders("Authorization")).andReturn(Collections.emptyEnumeration()); expect(request.getCookies()).andReturn(cookies); expect(request.getRemoteUser()).andReturn(null).times(2); diff --git a/cadc-util/src/test/java/ca/nrc/cadc/auth/TokenValidatorTest.java b/cadc-util/src/test/java/ca/nrc/cadc/auth/TokenValidatorTest.java index ace682a9..80003a0a 100644 --- a/cadc-util/src/test/java/ca/nrc/cadc/auth/TokenValidatorTest.java +++ b/cadc-util/src/test/java/ca/nrc/cadc/auth/TokenValidatorTest.java @@ -127,28 +127,16 @@ public void testValidateTokens() { subject = TokenValidator.validateTokens(subject); Assert.assertEquals("cookie credential", 1, subject.getPublicCredentials(SSOCookieCredential.class).size()); Assert.assertEquals("cookie principal", 0, subject.getPrincipals(AuthorizationTokenPrincipal.class).size()); - - // test cadc deprecated tokens - subject = new Subject(); - token = new SignedToken(new HttpPrincipal("user"), null, expiry, domains); - value = SignedToken.format(token); - AuthorizationTokenPrincipal authPrincipal = new AuthorizationTokenPrincipal(AuthenticationUtil.TOKEN_TYPE_CADC, value); - subject.getPrincipals().add(authPrincipal); - subject = TokenValidator.validateTokens(subject); - Assert.assertEquals("token credential", 1, subject.getPublicCredentials(AuthorizationToken.class).size()); - AuthorizationToken authToken = subject.getPublicCredentials(AuthorizationToken.class).iterator().next(); - Assert.assertEquals("cadc token type", AuthenticationUtil.TOKEN_TYPE_CADC, authToken.getType()); - Assert.assertEquals("cadc token value", value, authToken.getCredentials()); - + // bearer tokens subject = new Subject(); token = new SignedToken(new HttpPrincipal("user"), URI.create("the:scope"), expiry, domains); value = SignedToken.format(token); - authPrincipal = new AuthorizationTokenPrincipal(AuthenticationUtil.AUTHORIZATION_HEADER, "Bearer " + value); + AuthorizationTokenPrincipal authPrincipal = new AuthorizationTokenPrincipal(AuthenticationUtil.AUTHORIZATION_HEADER, "Bearer " + value); subject.getPrincipals().add(authPrincipal); subject = TokenValidator.validateTokens(subject); Assert.assertEquals("token credential", 1, subject.getPublicCredentials(AuthorizationToken.class).size()); - authToken = subject.getPublicCredentials(AuthorizationToken.class).iterator().next(); + AuthorizationToken authToken = subject.getPublicCredentials(AuthorizationToken.class).iterator().next(); Assert.assertEquals("bearer token type", AuthenticationUtil.CHALLENGE_TYPE_BEARER, authToken.getType()); Assert.assertEquals("bearer token value", value, authToken.getCredentials()); Assert.assertEquals("bearer token scope", "the:scope", authToken.getScope().toString()); From 5b98f3e96185d18baa3d39ad6fd9f3b53a6ba02f Mon Sep 17 00:00:00 2001 From: Adrian Damian Date: Thu, 17 Jul 2025 11:26:06 -0700 Subject: [PATCH 3/4] Fixed style --- .../src/main/java/ca/nrc/cadc/auth/TokenValidator.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cadc-util/src/main/java/ca/nrc/cadc/auth/TokenValidator.java b/cadc-util/src/main/java/ca/nrc/cadc/auth/TokenValidator.java index dbcd727c..37da422c 100644 --- a/cadc-util/src/main/java/ca/nrc/cadc/auth/TokenValidator.java +++ b/cadc-util/src/main/java/ca/nrc/cadc/auth/TokenValidator.java @@ -146,10 +146,10 @@ public static Subject validateTokens(Subject subject) throws NotAuthenticatedExc log.debug("Adding token credential to subject, removing token principal"); subject.getPublicCredentials().add(authToken); subject.getPrincipals().remove(p); - } // else: other kind of bearer token: leave AuthorizationTokenPrincipal for additional - // processing + } // else: other kind of bearer token: leave AuthorizationTokenPrincipal for more processing } catch (Exception ex) { - throw new NotAuthenticatedException(challengeType, AuthError.INVALID_TOKEN, ex.getMessage(), ex); + throw new NotAuthenticatedException( + challengeType, AuthError.INVALID_TOKEN, ex.getMessage(), ex); } } } From 677ef0f3a9e50f5c9137f55a1e2add1b2ac59855 Mon Sep 17 00:00:00 2001 From: Adrian Damian Date: Thu, 17 Jul 2025 14:05:15 -0700 Subject: [PATCH 4/4] Missed change --- .../src/main/java/ca/nrc/cadc/auth/AuthenticationUtil.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/cadc-util/src/main/java/ca/nrc/cadc/auth/AuthenticationUtil.java b/cadc-util/src/main/java/ca/nrc/cadc/auth/AuthenticationUtil.java index bc882982..c6e0876d 100644 --- a/cadc-util/src/main/java/ca/nrc/cadc/auth/AuthenticationUtil.java +++ b/cadc-util/src/main/java/ca/nrc/cadc/auth/AuthenticationUtil.java @@ -771,6 +771,9 @@ public static String getPrincipalType(Principal userID) { if (userID instanceof X500Principal) { return IdentityType.X500.getValue().toLowerCase(); } + if (userID instanceof OpenIdPrincipal) { + return IdentityType.OPENID.getValue().toLowerCase(); + } if (userID instanceof HttpPrincipal) { return IdentityType.USERNAME.getValue().toLowerCase(); }