1515import io .cos .cas .osf .authentication .exception .InstitutionSsoOsfApiFailedException ;
1616import io .cos .cas .osf .authentication .support .DelegationProtocol ;
1717import io .cos .cas .osf .authentication .support .OsfApiPermissionDenied ;
18+ import io .cos .cas .osf .authentication .support .OsfInstitutionUtils ;
1819import io .cos .cas .osf .configuration .model .OsfApiProperties ;
1920import io .cos .cas .osf .configuration .model .OsfUrlProperties ;
21+ import io .cos .cas .osf .dao .JpaOsfDao ;
2022import io .cos .cas .osf .web .support .OsfApiInstitutionAuthenticationResult ;
23+ import io .cos .cas .osf .web .support .OsfCasSsoErrorContext ;
2124
2225import com .nimbusds .jose .crypto .DirectEncrypter ;
2326import com .nimbusds .jose .crypto .MACSigner ;
141144@ Getter
142145public class OsfPrincipalFromNonInteractiveCredentialsAction extends AbstractNonInteractiveCredentialsAction {
143146
147+ private static final String PARAMETER_SSO_ERROR_CONTEXT = "osfCasSsoErrorContext" ;
148+
144149 private static final String USERNAME_PARAMETER_NAME = "username" ;
145150
146151 private static final String VERIFICATION_KEY_PARAMETER_NAME = "verification_key" ;
@@ -179,6 +184,9 @@ public class OsfPrincipalFromNonInteractiveCredentialsAction extends AbstractNon
179184 @ NotNull
180185 private CentralAuthenticationService centralAuthenticationService ;
181186
187+ @ NotNull
188+ private final JpaOsfDao jpaOsfDao ;
189+
182190 @ NotNull
183191 private OsfUrlProperties osfUrlProperties ;
184192
@@ -195,6 +203,7 @@ public OsfPrincipalFromNonInteractiveCredentialsAction(
195203 final CasWebflowEventResolver serviceTicketRequestWebflowEventResolver ,
196204 final AdaptiveAuthenticationPolicy adaptiveAuthenticationPolicy ,
197205 final CentralAuthenticationService centralAuthenticationService ,
206+ final JpaOsfDao jpaOsfDao ,
198207 final OsfUrlProperties osfUrlProperties ,
199208 final OsfApiProperties osfApiProperties ,
200209 final Map <String , List <String >> authnDelegationClients
@@ -205,6 +214,7 @@ public OsfPrincipalFromNonInteractiveCredentialsAction(
205214 adaptiveAuthenticationPolicy
206215 );
207216 this .centralAuthenticationService = centralAuthenticationService ;
217+ this .jpaOsfDao = jpaOsfDao ;
208218 this .osfUrlProperties = osfUrlProperties ;
209219 this .osfApiProperties = osfApiProperties ;
210220 this .authnDelegationClients = authnDelegationClients ;
@@ -240,7 +250,8 @@ protected Credential constructCredentialsFromRequest(final RequestContext contex
240250 );
241251 final OsfPostgresCredential osfPostgresCredential = constructCredentialsFromPac4jAuthentication (context , clientName );
242252 if (osfPostgresCredential != null ) {
243- final OsfApiInstitutionAuthenticationResult remoteUserInfo = notifyOsfApiOfInstnAuthnSuccess (osfPostgresCredential );
253+ final OsfApiInstitutionAuthenticationResult remoteUserInfo
254+ = notifyOsfApiOfInstnAuthnSuccess (context , osfPostgresCredential );
244255 osfPostgresCredential .setUsername (remoteUserInfo .getSsoEmail ());
245256 osfPostgresCredential .setInstitutionId (remoteUserInfo .getInstitutionId ());
246257 WebUtils .removeCredential (context );
@@ -263,7 +274,8 @@ protected Credential constructCredentialsFromRequest(final RequestContext contex
263274 // Type 3: institution sso via Shibboleth authentication using the SAML protocol
264275 LOGGER .debug ("Shibboleth session / header found in request context." );
265276 final OsfPostgresCredential osfPostgresCredential = constructCredentialsFromShibbolethAuthentication (context , request );
266- final OsfApiInstitutionAuthenticationResult remoteUserInfo = notifyOsfApiOfInstnAuthnSuccess (osfPostgresCredential );
277+ final OsfApiInstitutionAuthenticationResult remoteUserInfo
278+ = notifyOsfApiOfInstnAuthnSuccess (context , osfPostgresCredential );
267279 final String ssoIdentity = osfPostgresCredential .getSsoIdentity ();
268280 final String eppn = osfPostgresCredential .getDelegationAttributes ().get ("eppn" );
269281 final String mail = osfPostgresCredential .getDelegationAttributes ().get ("mail" );
@@ -568,6 +580,7 @@ private JSONObject extractInstnAuthnDataFromCredential(final OsfPostgresCredenti
568580 * @throws AccountException if there is an issue with authentication data or if the OSF API request has failed
569581 */
570582 private OsfApiInstitutionAuthenticationResult notifyOsfApiOfInstnAuthnSuccess (
583+ final RequestContext context ,
571584 final OsfPostgresCredential credential
572585 ) throws AccountException {
573586
@@ -758,6 +771,15 @@ private OsfApiInstitutionAuthenticationResult notifyOsfApiOfInstnAuthnSuccess(
758771 final String errorDetail = ((JsonObject ) error ).get ("detail" ).getAsString ();
759772 if (OsfApiPermissionDenied .INSTITUTION_SSO_SELECTIVE_LOGIN_DENIED .getId ().equals (errorDetail )) {
760773 LOGGER .error ("[OSF API] Failure - Institution Selective SSO Not Allowed: {}, filter={}" , ssoUser , selectiveSsoFilter );
774+ setSsoErrorContext (
775+ context ,
776+ InstitutionSsoSelectiveLoginDeniedException .class .getSimpleName (),
777+ String .format ("Institution Selective SSO Not Allowed: %s" , ssoUser ),
778+ ssoEmail ,
779+ ssoIdentity ,
780+ institutionId ,
781+ OsfInstitutionUtils .getInstitutionSupportEmail (this .jpaOsfDao , institutionId )
782+ );
761783 throw new InstitutionSsoSelectiveLoginDeniedException ("OSF API denies selective SSO login" );
762784 }
763785 if (OsfApiPermissionDenied .INSTITUTION_SSO_DUPLICATE_IDENTITY .getId ().equals (errorDetail )) {
@@ -810,4 +832,35 @@ private String retrieveDepartment(final String departmentRaw, final boolean eduP
810832 }
811833 return "" ;
812834 }
835+
836+ /**
837+ * Prepare {@link OsfCasSsoErrorContext} and put it in flow.
838+ *
839+ * @param context the request context
840+ * @param handleErrorName the error name
841+ * @param errorMessage the error message
842+ * @param ssoEmail user's SSO email
843+ * @param ssoIdentity user's SSO identity
844+ * @param institutionId institution ID
845+ * @param institutionSupportEmail institution support email
846+ */
847+ private void setSsoErrorContext (
848+ final RequestContext context ,
849+ final String handleErrorName ,
850+ final String errorMessage ,
851+ final String ssoEmail ,
852+ final String ssoIdentity ,
853+ final String institutionId ,
854+ final String institutionSupportEmail
855+ ) {
856+ OsfCasSsoErrorContext ssoErrorContext = new OsfCasSsoErrorContext (
857+ handleErrorName ,
858+ errorMessage ,
859+ ssoEmail ,
860+ ssoIdentity ,
861+ institutionId ,
862+ institutionSupportEmail
863+ );
864+ context .getFlowScope ().put (PARAMETER_SSO_ERROR_CONTEXT , ssoErrorContext );
865+ }
813866}
0 commit comments