From 01280237d7d03a663394c5bd7ab73b5df1bae022 Mon Sep 17 00:00:00 2001 From: Longze Chen Date: Sun, 6 Sep 2026 23:28:00 -0400 Subject: [PATCH] Add OrcidSsoFailedException with error flow/page --- .../exception/OrcidSsoFailedException.java | 27 +++++++++++++ .../OsfOrcidSsoAuthenticationHandler.java | 14 ++++--- .../OsfCasCoreWebflowConfiguration.java | 2 + .../OsfCasLoginWebflowConfigurer.java | 11 +++++ .../flow/support/OsfCasWebflowConstants.java | 4 ++ src/main/resources/messages.properties | 6 +++ .../templates/casOrcidSsoFailedView.html | 40 +++++++++++++++++++ 7 files changed, 98 insertions(+), 6 deletions(-) create mode 100644 src/main/java/io/cos/cas/osf/authentication/exception/OrcidSsoFailedException.java create mode 100644 src/main/resources/templates/casOrcidSsoFailedView.html diff --git a/src/main/java/io/cos/cas/osf/authentication/exception/OrcidSsoFailedException.java b/src/main/java/io/cos/cas/osf/authentication/exception/OrcidSsoFailedException.java new file mode 100644 index 00000000..0b373339 --- /dev/null +++ b/src/main/java/io/cos/cas/osf/authentication/exception/OrcidSsoFailedException.java @@ -0,0 +1,27 @@ +package io.cos.cas.osf.authentication.exception; + +import lombok.NoArgsConstructor; + +import javax.security.auth.login.AccountException; + +/** + * Describes an authentication error condition where ORCiD SSO has failed due to missing id or token(s). + * + * @author Longze Chen + * @since 26.2.0 + */ +@NoArgsConstructor +public class OrcidSsoFailedException extends AccountException { + + /** Serial version UID. */ + private static final long serialVersionUID = 7499754046067009352L; + + /** + * Instantiates a new {@link OrcidSsoFailedException}. + * + * @param msg the msg + */ + public OrcidSsoFailedException(final String msg) { + super(msg); + } +} diff --git a/src/main/java/io/cos/cas/osf/authentication/handler/support/OsfOrcidSsoAuthenticationHandler.java b/src/main/java/io/cos/cas/osf/authentication/handler/support/OsfOrcidSsoAuthenticationHandler.java index f489fa9b..a6ab0615 100644 --- a/src/main/java/io/cos/cas/osf/authentication/handler/support/OsfOrcidSsoAuthenticationHandler.java +++ b/src/main/java/io/cos/cas/osf/authentication/handler/support/OsfOrcidSsoAuthenticationHandler.java @@ -1,6 +1,7 @@ package io.cos.cas.osf.authentication.handler.support; import io.cos.cas.osf.authentication.credential.OsfOrcidSsoCredential; +import io.cos.cas.osf.authentication.exception.OrcidSsoFailedException; import lombok.extern.slf4j.Slf4j; import lombok.Getter; @@ -71,8 +72,8 @@ protected final AuthenticationHandlerExecutionResult authenticateOsfOrcidSsoInte ) throws GeneralSecurityException { if (credential == null) { - LOGGER.error("[ORCiD SSO] Null/Empty ORCiD Credential."); - throw new GeneralSecurityException("Null/Empty ORCiD Credential."); + LOGGER.error("[ORCiD SSO] ERROR: Null/Empty ORCiD Credential."); + throw new OrcidSsoFailedException("Null/Empty ORCiD Credential."); } final String credentialId = credential.getId(); @@ -81,11 +82,12 @@ protected final AuthenticationHandlerExecutionResult authenticateOsfOrcidSsoInte final String orcidRefreshToken = credential.getOrcidRefreshToken(); if (StringUtils.isBlank(orcidId)) { - LOGGER.error("[ORCiD SSO] Null/Empty ORCiD ID."); - throw new GeneralSecurityException("Null/Empty ORCiD ID."); + LOGGER.error("[ORCiD SSO] ERROR: Null/Empty ORCiD ID."); + throw new OrcidSsoFailedException("Null/Empty ORCiD ID."); } else if (StringUtils.isBlank(orcidAccessToken)) { - LOGGER.error("[ORCiD SSO] Null/Empty ORCiD Access Token, orcidId=[{}]", orcidId); - throw new GeneralSecurityException("Null/Empty ORCiD Access Token."); + // TODO: should we only log error but let authentication pass? + LOGGER.error("[ORCiD SSO] ERROR: Null/Empty ORCiD Access Token, orcidId=[{}]", orcidId); + throw new OrcidSsoFailedException("Null/Empty ORCiD Access Token."); } LOGGER.info( diff --git a/src/main/java/io/cos/cas/osf/web/flow/config/OsfCasCoreWebflowConfiguration.java b/src/main/java/io/cos/cas/osf/web/flow/config/OsfCasCoreWebflowConfiguration.java index 7014d3d0..255335dd 100644 --- a/src/main/java/io/cos/cas/osf/web/flow/config/OsfCasCoreWebflowConfiguration.java +++ b/src/main/java/io/cos/cas/osf/web/flow/config/OsfCasCoreWebflowConfiguration.java @@ -15,6 +15,7 @@ import io.cos.cas.osf.authentication.exception.InvalidUserStatusException; import io.cos.cas.osf.authentication.exception.InvalidVerificationKeyException; import io.cos.cas.osf.authentication.exception.OneTimePasswordRequiredException; +import io.cos.cas.osf.authentication.exception.OrcidSsoFailedException; import io.cos.cas.osf.authentication.exception.TermsOfServiceConsentRequiredException; import org.apereo.cas.configuration.CasConfigurationProperties; @@ -62,6 +63,7 @@ public Set> handledAuthenticationExceptions() { errors.add(InvalidUserStatusException.class); errors.add(InvalidVerificationKeyException.class); errors.add(OneTimePasswordRequiredException.class); + errors.add(OrcidSsoFailedException.class); errors.add(TermsOfServiceConsentRequiredException.class); // Add built-in exceptions after OSF-specific exceptions since order matters diff --git a/src/main/java/io/cos/cas/osf/web/flow/configurer/OsfCasLoginWebflowConfigurer.java b/src/main/java/io/cos/cas/osf/web/flow/configurer/OsfCasLoginWebflowConfigurer.java index d232f6db..386cddb5 100644 --- a/src/main/java/io/cos/cas/osf/web/flow/configurer/OsfCasLoginWebflowConfigurer.java +++ b/src/main/java/io/cos/cas/osf/web/flow/configurer/OsfCasLoginWebflowConfigurer.java @@ -15,6 +15,7 @@ import io.cos.cas.osf.authentication.exception.InvalidUserStatusException; import io.cos.cas.osf.authentication.exception.InvalidVerificationKeyException; import io.cos.cas.osf.authentication.exception.OneTimePasswordRequiredException; +import io.cos.cas.osf.authentication.exception.OrcidSsoFailedException; import io.cos.cas.osf.authentication.exception.TermsOfServiceConsentRequiredException; import io.cos.cas.osf.web.flow.support.OsfCasWebflowConstants; @@ -301,6 +302,11 @@ protected void createHandleAuthenticationFailureAction(final Flow flow) { TermsOfServiceConsentRequiredException.class.getSimpleName(), OsfCasWebflowConstants.VIEW_ID_TERMS_OF_SERVICE_CONSENT_REQUIRED ); + createTransitionForState( + handler, + OrcidSsoFailedException.class.getSimpleName(), + OsfCasWebflowConstants.VIEW_ID_ORCID_SSO_FAILED + ); // The default transition createStateDefaultTransition(handler, CasWebflowConstants.STATE_ID_INIT_LOGIN_FORM); @@ -481,6 +487,11 @@ private void createOsfCasAuthenticationExceptionViewStates(final Flow flow) { OsfCasWebflowConstants.VIEW_ID_INSTITUTION_SSO_MULTIPLE_EMAILS_NOT_SUPPORTED, OsfCasWebflowConstants.VIEW_ID_INSTITUTION_SSO_MULTIPLE_EMAILS_NOT_SUPPORTED ); + createViewState( + flow, + OsfCasWebflowConstants.VIEW_ID_ORCID_SSO_FAILED, + OsfCasWebflowConstants.VIEW_ID_ORCID_SSO_FAILED + ); } /** diff --git a/src/main/java/io/cos/cas/osf/web/flow/support/OsfCasWebflowConstants.java b/src/main/java/io/cos/cas/osf/web/flow/support/OsfCasWebflowConstants.java index 6f938981..17a90a04 100644 --- a/src/main/java/io/cos/cas/osf/web/flow/support/OsfCasWebflowConstants.java +++ b/src/main/java/io/cos/cas/osf/web/flow/support/OsfCasWebflowConstants.java @@ -60,6 +60,10 @@ public interface OsfCasWebflowConstants { String VIEW_ID_INVALID_VERIFICATION_KEY = "casInvalidVerificationKeyView"; + // Exception Views for ORCiD SSO + + String VIEW_ID_ORCID_SSO_FAILED = "casOrcidSsoFailedView"; + // Exception Views for Institution SSO String VIEW_ID_INSTITUTION_SSO_ACCOUNT_INACTIVE = "casInstitutionSsoAccountInactiveView"; diff --git a/src/main/resources/messages.properties b/src/main/resources/messages.properties index a6a68470..d65b3ec2 100644 --- a/src/main/resources/messages.properties +++ b/src/main/resources/messages.properties @@ -712,6 +712,12 @@ screen.onetimepasswordrequired.heading=OSF Two-factor Authentication screen.onetimepasswordrequired.message=Two-factor authentication has been enabled for this OSF account. Please enter \ the one-time password generated by the authentication app. If you believe this should not happen, please contact OSF Support. +screen.orcidssofailed.title=ORCiD SSO Error +screen.orcidssofailed.heading=ORCiD login failed +screen.orcidssofailed.message=\ + Your request cannot be completed at this time due to an unexpected error. \ + Please return to OSF and try again later. \ + If the issue persists, contact Support for help. screen.institutionssofailed.title=Institution SSO Error screen.institutionssofailed.heading=Institution login failed screen.institutionssofailed.message=\ diff --git a/src/main/resources/templates/casOrcidSsoFailedView.html b/src/main/resources/templates/casOrcidSsoFailedView.html new file mode 100644 index 00000000..b73490e8 --- /dev/null +++ b/src/main/resources/templates/casOrcidSsoFailedView.html @@ -0,0 +1,40 @@ + + + + + + + + + + + + +
+ +
+ +
+ + + +
+ + +