[java-idp-plugin-oidc-rp] branch main updated: Add audit logging. Cleanup the flow.
Phil Smart
philip.smart at jisc.ac.uk
Wed Aug 31 09:27:42 UTC 2022
This is an automated email from the git hooks/post-receive script.
philsmart pushed a commit to branch main
in repository java-idp-plugin-oidc-rp.
View the commit online:
http://git.shibboleth.net/view/?p=java-idp-plugin-oidc-rp.git;a=commit;h=5a008ebdd251b4b50fc2380e0276a2eb31ec4385
The following commit(s) were added to refs/heads/main by this push:
new 5a008eb Add audit logging. Cleanup the flow.
5a008eb is described below
commit 5a008ebdd251b4b50fc2380e0276a2eb31ec4385
Author: Phil Smart <philip.smart at jisc.ac.uk>
AuthorDate: Wed Aug 31 10:27:36 2022 +0100
Add audit logging. Cleanup the flow.
---
.../impl/AbstractHttpOIDCAuthenticationAction.java | 2 +-
.../AbstractOIDCAuthenticationResponseAction.java | 10 +-
.../impl/DefaultEndUserClaimsLookupStrategy.java | 74 +++++++
.../rp/impl/UnsupportedResponseTypeAction.java | 45 ++++
.../authn/oidc/rp/impl/UserInfoEndpointLookup.java | 1 -
.../META-INF/net.shibboleth.idp/postconfig.xml | 236 ++++++++++++++++++++-
.../oidc-relying-party-authn-beans.xml | 41 ++--
.../oidc-relying-party-authn-flow.xml | 90 ++++----
.../ProxyAuthenticationFlowAuditExtractor.java | 51 +++++
.../plugin/authn/oidc/rp/impl/OIDCRPFlowTest.java | 75 ++++++-
.../plugin/authn/oidc/rp/impl/TestTokenHelper.java | 1 +
.../flow/AbstractAuthnXmlFlowExecutionTests.java | 3 +
idp-oidc-rp-impl/src/test/resources/conf/audit.xml | 74 +++++++
.../src/test/resources/logback-test.xml | 8 +-
14 files changed, 628 insertions(+), 83 deletions(-)
diff --git a/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/AbstractHttpOIDCAuthenticationAction.java b/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/AbstractHttpOIDCAuthenticationAction.java
index 738a730..3ce3c36 100644
--- a/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/AbstractHttpOIDCAuthenticationAction.java
+++ b/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/AbstractHttpOIDCAuthenticationAction.java
@@ -44,7 +44,7 @@ import net.shibboleth.utilities.java.support.logic.Constraint;
*
* @param <T> the response type of the object returned as a result of the request.
*/
-public class AbstractHttpOIDCAuthenticationAction<T> extends AbstractOIDCAuthenticationResponseAction {
+public abstract class AbstractHttpOIDCAuthenticationAction<T> extends AbstractOIDCAuthenticationResponseAction {
/** Class logger.*/
@Nonnull private final Logger log = LoggerFactory.getLogger(AbstractHttpOIDCAuthenticationAction.class);
diff --git a/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/AbstractOIDCAuthenticationResponseAction.java b/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/AbstractOIDCAuthenticationResponseAction.java
index 085c60a..18bcc46 100644
--- a/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/AbstractOIDCAuthenticationResponseAction.java
+++ b/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/AbstractOIDCAuthenticationResponseAction.java
@@ -45,10 +45,10 @@ import net.shibboleth.utilities.java.support.logic.Constraint;
/**
*
* Abstract class for actions performing actions on {@link AuthenticationResponse} located under
- * {@link ProfileRequestContext#getOutboundMessageContext()#getM}.
+ * the {@link ProfileRequestContext#getOutboundMessageContext())}.
*
*/
-abstract class AbstractOIDCAuthenticationResponseAction extends AbstractAuthenticationAction {
+public abstract class AbstractOIDCAuthenticationResponseAction extends AbstractAuthenticationAction {
/** Class logger. */
@Nonnull private final Logger log = LoggerFactory.getLogger(AbstractOIDCAuthenticationResponseAction.class);
@@ -92,7 +92,7 @@ abstract class AbstractOIDCAuthenticationResponseAction extends AbstractAuthenti
*
* @return the authentication response.
*/
- @Nullable public AuthenticationSuccessResponse getAuthenticationResponse() {
+ @Nullable protected AuthenticationSuccessResponse getAuthenticationResponse() {
return authnResponse;
}
@@ -101,7 +101,7 @@ abstract class AbstractOIDCAuthenticationResponseAction extends AbstractAuthenti
*
* @return the authentication request.
*/
- @Nullable public OIDCAuthenticationRequest getAuthenticationRequest() {
+ @Nullable protected OIDCAuthenticationRequest getAuthenticationRequest() {
return authnRequest;
}
@@ -111,7 +111,7 @@ abstract class AbstractOIDCAuthenticationResponseAction extends AbstractAuthenti
*
* @return The provider metadata context.
*/
- @Nullable public OIDCProviderMetadataContext getProviderMetadataContext() {
+ @Nullable protected OIDCProviderMetadataContext getProviderMetadataContext() {
return providerMetadataContext;
}
diff --git a/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/DefaultEndUserClaimsLookupStrategy.java b/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/DefaultEndUserClaimsLookupStrategy.java
new file mode 100644
index 0000000..0cf9d83
--- /dev/null
+++ b/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/DefaultEndUserClaimsLookupStrategy.java
@@ -0,0 +1,74 @@
+/*
+ * Licensed to the University Corporation for Advanced Internet Development,
+ * Inc. (UCAID) under one or more contributor license agreements. See the
+ * NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The UCAID licenses this file to You under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.shibboleth.idp.plugin.authn.oidc.rp.impl;
+
+import java.util.function.Function;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import javax.annotation.concurrent.ThreadSafe;
+
+import org.opensaml.messaging.context.navigate.ChildContextLookup;
+import org.opensaml.profile.context.ProfileRequestContext;
+import org.opensaml.profile.context.navigate.InboundMessageContextLookup;
+
+import com.nimbusds.openid.connect.sdk.claims.ClaimsSet;
+
+import net.shibboleth.idp.plugin.authn.oidc.rp.context.EndUserClaimsContext;
+import net.shibboleth.utilities.java.support.annotation.ParameterName;
+import net.shibboleth.utilities.java.support.logic.Constraint;
+
+/** Function that extracts the end-user's claims from the {@link EndUserClaimsContext}.*/
+ at ThreadSafe
+public class DefaultEndUserClaimsLookupStrategy implements Function<ProfileRequestContext, ClaimsSet> {
+
+ /** Strategy used to look up the {@link EndUserClaimsContext}. */
+ @Nonnull
+ private final Function<ProfileRequestContext, EndUserClaimsContext> endUserClaimsContextLookupStrategy;
+
+ /**
+ *
+ * Constructor.
+ *
+ * @param strategy the end-user claims context lookup strategy to use.
+ */
+ public DefaultEndUserClaimsLookupStrategy(@Nullable @ParameterName(name="endUserClaimsContextLookupStrategy")
+ final Function<ProfileRequestContext, EndUserClaimsContext> strategy) {
+ if (strategy != null) {
+ endUserClaimsContextLookupStrategy =
+ Constraint.isNotNull(strategy, "EndUserClaimsContext lookup strategy can not be null");
+ } else {
+ endUserClaimsContextLookupStrategy =
+ new ChildContextLookup<>(EndUserClaimsContext.class).compose(
+ new InboundMessageContextLookup());
+ }
+ }
+
+
+ @Override
+ @Nullable public ClaimsSet apply(@Nonnull final ProfileRequestContext prc) {
+
+ final EndUserClaimsContext endUserContext = endUserClaimsContextLookupStrategy.apply(prc);
+
+ if (endUserContext != null && endUserContext.getEndUserClaims() != null) {
+ return endUserContext.getEndUserClaims();
+ }
+ return null;
+ }
+
+}
diff --git a/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/UnsupportedResponseTypeAction.java b/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/UnsupportedResponseTypeAction.java
new file mode 100644
index 0000000..feee9c7
--- /dev/null
+++ b/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/UnsupportedResponseTypeAction.java
@@ -0,0 +1,45 @@
+/*
+ * Licensed to the University Corporation for Advanced Internet Development,
+ * Inc. (UCAID) under one or more contributor license agreements. See the
+ * NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The UCAID licenses this file to You under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.shibboleth.idp.plugin.authn.oidc.rp.impl;
+
+import javax.annotation.Nonnull;
+
+import org.opensaml.profile.action.ActionSupport;
+import org.opensaml.profile.context.ProfileRequestContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import net.shibboleth.idp.profile.AbstractProfileAction;
+import net.shibboleth.oidc.profile.core.OidcEventIds;
+
+/** Simple action to log the response was to an unsupported grant type.*/
+public class UnsupportedResponseTypeAction extends AbstractProfileAction {
+
+ /** Class logger. */
+ @Nonnull private final Logger log = LoggerFactory.getLogger(UnsupportedResponseTypeAction.class);
+
+ @Override
+ protected void doExecute(@Nonnull final ProfileRequestContext profileRequestContext) {
+ log.error("{} Response type is not supported", getLogPrefix());
+ ActionSupport.buildEvent(profileRequestContext, OidcEventIds.INVALID_RESPONSE_TYPE);
+ return;
+ }
+
+
+
+}
diff --git a/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/UserInfoEndpointLookup.java b/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/UserInfoEndpointLookup.java
index 615fa12..29370c5 100644
--- a/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/UserInfoEndpointLookup.java
+++ b/idp-oidc-rp-impl/src/main/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/UserInfoEndpointLookup.java
@@ -89,7 +89,6 @@ public class UserInfoEndpointLookup extends AbstractHttpOIDCAuthenticationAction
try {
final UserInfoResponse responseObject = handleRequest(profileRequestContext);
userInfoCtx.setUserInfo(responseObject);
-
} catch (final OIDCRPException e) {
log.error("{} Unable to return claims from UserInfo endpoint",getLogPrefix(),e);
ActionSupport.buildEvent(profileRequestContext, AuthnEventIds.AUTHN_EXCEPTION);
diff --git a/idp-oidc-rp-impl/src/main/resources/META-INF/net.shibboleth.idp/postconfig.xml b/idp-oidc-rp-impl/src/main/resources/META-INF/net.shibboleth.idp/postconfig.xml
index d19dd9a..e021f89 100644
--- a/idp-oidc-rp-impl/src/main/resources/META-INF/net.shibboleth.idp/postconfig.xml
+++ b/idp-oidc-rp-impl/src/main/resources/META-INF/net.shibboleth.idp/postconfig.xml
@@ -117,13 +117,24 @@
<bean id="shibboleth.ChildLookup.Proxy.MessageContextLookup.Outbound"
class="net.shibboleth.idp.plugin.authn.oidc.rp.config.navigate.OutboundMessageContextFromProxyPRC"/>
+ <bean id="shibboleth.MessageLookup.oidc.rp.OIDCAuthenticationRequest"
+ class="org.opensaml.messaging.context.navigate.MessageLookup"
+ c:type="#{ T(net.shibboleth.oidc.profile.core.OIDCAuthenticationRequest) }" />
+
+ <bean id="shibboleth.MessageLookup.oidc.rp.AuthenticationResponse"
+ class="org.opensaml.messaging.context.navigate.MessageLookup"
+ c:type="#{ T(com.nimbusds.openid.connect.sdk.AuthenticationResponse) }" />
+
<!-- Aliases to use in the flow config -->
<alias name="shibboleth.ChildLookup.Proxy.MessageContextLookup.Inbound" alias="InboundMessageContextFromRootPRC"/>
<alias name="shibboleth.ChildLookup.Proxy.MessageContextLookup.Outbound" alias="OutboundMessageContextFromRootPRC"/>
<alias name="shibboleth.ChildLookup.Proxy.ProxyProfileRequestContext" alias="ProxyProfileRequestContextLookup"/>
-
+ <!-- lookup strategies required by the postconfig in addition to the flow -->
+ <bean id="shibboleth.authn.oidc.rp.DefaultIDTokenLookupStrategy"
+ class="net.shibboleth.idp.plugin.authn.oidc.rp.impl.DefaultIDTokenLookupStrategy" />
+
<!-- The authentication flow descriptor -->
<bean id="authn/OIDCRelyingParty" parent="shibboleth.AuthenticationFlow"
@@ -212,37 +223,246 @@
<!--
- Add some auditors, should be in the audit-system.xml
+ Some RP audit extractors
-->
+
+ <bean id="shibboleth.oidc.rp.DefaultPostLookupAuditExtractors" lazy-init="true"
+ class="org.springframework.beans.factory.config.MapFactoryBean">
+ <property name="sourceMap">
+ <map>
+ <entry>
+ <key>
+ <util:constant static-field="net.shibboleth.idp.authn.AuthnAuditFields.AUTHN_FLOW_ID"/>
+ </key>
+ <bean class="net.shibboleth.idp.plugin.authn.oidc.rp.audit.impl.ProxyAuthenticationFlowAuditExtractor" />
+ </entry>
+
+ <entry>
+ <key>
+ <util:constant static-field="net.shibboleth.oidc.profile.audit.AuditFields.PROXY_ISSUER"/>
+ </key>
+ <ref bean="shibboleth.RelyingPartyIdLookup.Simple" />
+ </entry>
+ <entry>
+ <key>
+ <util:constant static-field="net.shibboleth.oidc.profile.audit.AuditFields.PROXY_CLIENT_ID"/>
+ </key>
+ <ref bean="shibboleth.ResponderIdLookup.Simple" />
+ </entry>
+ </map>
+ </property>
+ </bean>
+
+ <bean id="shibboleth.oidc.rp.DefaultPostRequestAuditExtractors" lazy-init="true"
+ class="org.springframework.beans.factory.config.MapFactoryBean">
+ <property name="sourceMap">
+ <map>
+ <entry>
+ <key>
+ <util:constant static-field="net.shibboleth.oidc.profile.audit.AuditFields.RESPONSE_TYPE"/>
+ </key>
+ <bean class="net.shibboleth.oidc.profile.audit.impl.ResponseTypeAuditExtractor">
+ <constructor-arg>
+ <bean parent="shibboleth.Functions.Compose"
+ c:g-ref="shibboleth.MessageLookup.oidc.rp.OIDCAuthenticationRequest"
+ c:f-ref="shibboleth.MessageContextLookup.Outbound" />
+ </constructor-arg>
+ </bean>
+ </entry>
+ <entry>
+ <key>
+ <util:constant static-field="net.shibboleth.oidc.profile.audit.AuditFields.RESPONSE_MODE"/>
+ </key>
+ <bean class="net.shibboleth.oidc.profile.audit.impl.ResponseModeAuditExtractor">
+ <constructor-arg>
+ <bean parent="shibboleth.Functions.Compose"
+ c:g-ref="shibboleth.MessageLookup.oidc.rp.OIDCAuthenticationRequest"
+ c:f-ref="shibboleth.MessageContextLookup.Outbound" />
+ </constructor-arg>
+ </bean>
+ </entry>
+ <entry>
+ <key>
+ <util:constant static-field="net.shibboleth.oidc.profile.audit.AuditFields.SCOPE"/>
+ </key>
+ <bean class="net.shibboleth.oidc.profile.audit.impl.ScopeAuditExtractor">
+ <constructor-arg>
+ <bean parent="shibboleth.Functions.Compose"
+ c:g-ref="shibboleth.MessageLookup.oidc.rp.OIDCAuthenticationRequest"
+ c:f-ref="shibboleth.MessageContextLookup.Outbound" />
+ </constructor-arg>
+ </bean>
+ </entry>
+ <entry>
+ <key>
+ <util:constant static-field="net.shibboleth.oidc.profile.audit.AuditFields.FORCE_AUTHN"/>
+ </key>
+ <bean class="net.shibboleth.oidc.profile.audit.impl.ForceAuthnAuditExtractor">
+ <constructor-arg>
+ <bean parent="shibboleth.Functions.Compose"
+ c:g-ref="shibboleth.MessageLookup.oidc.rp.OIDCAuthenticationRequest"
+ c:f-ref="shibboleth.MessageContextLookup.Outbound" />
+ </constructor-arg>
+ </bean>
+ </entry>
+ <entry>
+ <key>
+ <util:constant
+ static-field="net.shibboleth.oidc.profile.audit.AuditFields.NONCE"/>
+ </key>
+ <bean class="net.shibboleth.oidc.profile.audit.impl.NonceAuditExtractor">
+ <constructor-arg>
+ <bean parent="shibboleth.Functions.Compose"
+ c:g-ref="shibboleth.MessageLookup.oidc.rp.OIDCAuthenticationRequest"
+ c:f-ref="shibboleth.MessageContextLookup.Outbound" />
+ </constructor-arg>
+ </bean>
+ </entry>
+ <entry>
+ <key>
+ <util:constant
+ static-field="net.shibboleth.oidc.profile.audit.AuditFields.AUTHORIZATION_ENDPOINT"/>
+ </key>
+ <bean class="net.shibboleth.oidc.profile.audit.impl.AuthorizationEndpointAuditExtractor">
+ <constructor-arg>
+ <bean parent="shibboleth.Functions.Compose"
+ c:g-ref="shibboleth.MessageLookup.oidc.rp.OIDCAuthenticationRequest"
+ c:f-ref="shibboleth.MessageContextLookup.Outbound" />
+ </constructor-arg>
+ </bean>
+ </entry>
+ <entry>
+ <key>
+ <util:constant
+ static-field="net.shibboleth.oidc.profile.audit.AuditFields.REDIRECT_URI"/>
+ </key>
+ <bean class="net.shibboleth.oidc.profile.audit.impl.RedirectURIAuditExtractor">
+ <constructor-arg>
+ <bean parent="shibboleth.Functions.Compose"
+ c:g-ref="shibboleth.MessageLookup.oidc.rp.OIDCAuthenticationRequest"
+ c:f-ref="shibboleth.MessageContextLookup.Outbound" />
+ </constructor-arg>
+ </bean>
+ </entry>
+ <entry>
+ <key>
+ <util:constant
+ static-field="net.shibboleth.oidc.profile.audit.AuditFields.REDIRECT_URI"/>
+ </key>
+ <bean class="net.shibboleth.oidc.profile.audit.impl.RedirectURIAuditExtractor">
+ <constructor-arg>
+ <bean parent="shibboleth.Functions.Compose"
+ c:g-ref="shibboleth.MessageLookup.oidc.rp.OIDCAuthenticationRequest"
+ c:f-ref="shibboleth.MessageContextLookup.Outbound" />
+ </constructor-arg>
+ </bean>
+ </entry>
+ <entry>
+ <key>
+ <util:constant static-field="net.shibboleth.oidc.profile.audit.AuditFields.ACRS"/>
+ </key>
+ <bean class="net.shibboleth.oidc.profile.audit.impl.AuthenticationContextClassReferencesAuditExtractor">
+ <constructor-arg>
+ <bean parent="shibboleth.Functions.Compose"
+ c:g-ref="shibboleth.MessageLookup.oidc.rp.OIDCAuthenticationRequest"
+ c:f-ref="shibboleth.MessageContextLookup.Outbound" />
+ </constructor-arg>
+ </bean>
+ </entry>
+ </map>
+ </property>
+ </bean>
<bean id="shibboleth.oidc.rp.DefaultAuthenticationResponseAuditExtractors" lazy-init="true"
class="org.springframework.beans.factory.config.MapFactoryBean">
<property name="sourceMap">
<map>
- <!-- No entries for now -->
+ <entry>
+ <key>
+ <util:constant
+ static-field="net.shibboleth.oidc.profile.audit.AuditFields.INBOUND_MESSAGE_CLASS" />
+ </key>
+ <bean class="net.shibboleth.oidc.profile.audit.impl.InboundMessageClassLookupFunction" />
+ </entry>
+ <entry>
+ <key>
+ <util:constant static-field="net.shibboleth.oidc.profile.audit.AuditFields.AUTHENTICATION_RESULT"/>
+ </key>
+ <bean class="net.shibboleth.oidc.profile.audit.impl.AuthenticationResponseStatusAuditExtractor">
+ <constructor-arg>
+ <bean parent="shibboleth.Functions.Compose"
+ c:g-ref="shibboleth.MessageLookup.oidc.rp.AuthenticationResponse"
+ c:f-ref="shibboleth.MessageContextLookup.Inbound" />
+ </constructor-arg>
+ </bean>
+ </entry>
</map>
</property>
</bean>
-
+ <bean id="shibboleth.authn.oidc.rp.DefaultIDTokenClaimsSetLookupStrategy"
+ class="net.shibboleth.oidc.profile.audit.impl.ClaimSetFromJWTLookupStrategy"
+ c:jwtLookupStrategy-ref="shibboleth.authn.oidc.rp.DefaultIDTokenLookupStrategy">
+ </bean>
+
+ <bean id="shibboleth.authn.oidc.rp.DefaultEndUserClaimsLookupStrategy"
+ class="net.shibboleth.idp.plugin.authn.oidc.rp.impl.DefaultEndUserClaimsLookupStrategy"
+ c:endUserClaimsContextLookupStrategy="#{getObject('shibboleth.authn.oidc.rp.EndUserClaimsContextLookupStrategy')}"/>
+
<bean id="shibboleth.oidc.rp.DefaultTokenResponseAuditExtractors" lazy-init="true"
class="org.springframework.beans.factory.config.MapFactoryBean">
<property name="sourceMap">
<map>
- <!-- No entries for now -->
+ <entry>
+ <key>
+ <util:constant
+ static-field="net.shibboleth.oidc.profile.audit.AuditFields.SUB_VALUE" />
+ </key>
+ <bean class="net.shibboleth.oidc.profile.audit.impl.StringBasedJWTClaimAuditExtractor"
+ p:claimName="sub"
+ p:claimsSetLookupStrategy-ref="shibboleth.authn.oidc.rp.DefaultIDTokenClaimsSetLookupStrategy"/>
+ </entry>
+ <entry>
+ <key>
+ <util:constant
+ static-field="net.shibboleth.oidc.profile.audit.AuditFields.AUDIENCE" />
+ </key>
+ <bean class="net.shibboleth.oidc.profile.audit.impl.StringListBasedJWTClaimAuditExtractor"
+ p:claimName="aud"
+ p:claimsSetLookupStrategy-ref="shibboleth.authn.oidc.rp.DefaultIDTokenClaimsSetLookupStrategy"/>
+ </entry>
+ <entry>
+ <key>
+ <util:constant
+ static-field="net.shibboleth.oidc.profile.audit.AuditFields.AUTHN_INSTANT" />
+ </key>
+ <bean class="net.shibboleth.oidc.profile.audit.impl.DateBasedJWTClaimAuditExtractor"
+ p:claimName="auth_time"
+ p:claimsSetLookupStrategy-ref="shibboleth.authn.oidc.rp.DefaultIDTokenClaimsSetLookupStrategy"/>
+ </entry>
</map>
</property>
</bean>
-
- <bean id="shibboleth.oidc.rp.DefaultUserInfoResponseAuditExtractors" lazy-init="true"
+ <!-- Extract audit information post id_token and (if configured) userinfo response. Nothing by default. -->
+ <bean id="shibboleth.oidc.rp.DefaultPostResponseAuditExtractors" lazy-init="true"
class="org.springframework.beans.factory.config.MapFactoryBean">
<property name="sourceMap">
<map>
- <!-- No entries for now -->
+ <!-- <entry>
+ <key>
+ <util:constant
+ static-field="net.shibboleth.oidc.profile.audit.AuditFields.FIELD" />
+ </key>
+ <bean class="net.shibboleth.oidc.profile.audit.impl.StringBasedJWTClaimAuditExtractor"
+ p:claimName="name"
+ p:claimsSetLookupStrategy-ref="shibboleth.authn.oidc.rp.DefaultEndUserClaimsLookupStrategy"/>
+ </entry> -->
</map>
</property>
</bean>
+
+
</beans>
\ No newline at end of file
diff --git a/idp-oidc-rp-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/authn/OIDCRelyingParty/oidc-relying-party-authn-beans.xml b/idp-oidc-rp-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/authn/OIDCRelyingParty/oidc-relying-party-authn-beans.xml
index 40182e4..242b84f 100644
--- a/idp-oidc-rp-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/authn/OIDCRelyingParty/oidc-relying-party-authn-beans.xml
+++ b/idp-oidc-rp-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/authn/OIDCRelyingParty/oidc-relying-party-authn-beans.xml
@@ -100,7 +100,7 @@
<!-- TODO check shibboleth.oidc.rp is sensible in the getObjects -->
<bean id="PostLookupPopulateAuditContext" parent="shibboleth.AbstractPopulateAuditContext"
p:profileContextLookupStrategy-ref="shibboleth.ChildLookup.ProxyProfileRequestContext"
- p:fieldExtractors="#{getObject('shibboleth.oidc.rp.PostLookupAuditExtractors') ?: getObject('shibboleth.DefaultPostLookupAuditExtractors')}" />
+ p:fieldExtractors="#{getObject('shibboleth.oidc.rp.PostLookupAuditExtractors') ?: getObject('shibboleth.oidc.rp.DefaultPostLookupAuditExtractors')}" />
<bean id="InitializeAuthorizationRequest"
@@ -151,12 +151,8 @@
<bean id="PostRequestPopulateAuditContext" parent="shibboleth.AbstractPopulateAuditContext"
p:profileContextLookupStrategy-ref="shibboleth.ChildLookup.ProxyProfileRequestContext"
- p:fieldExtractors="#{getObject('shibboleth.oidc.rp.PostRequestAuditExtractors') ?: getObject('shibboleth.DefaultPostRequestAuditExtractors')}" />
-
- <bean id="AuthenticationResponsePopulateAuditContext" parent="shibboleth.AbstractPopulateAuditContext"
- p:profileContextLookupStrategy-ref="shibboleth.ChildLookup.ProxyProfileRequestContext"
- p:fieldExtractors="#{getObject('shibboleth.oidc.rp.AuthenticationResponseAuditExtractors') ?: getObject('shibboleth.oidc.rp.DefaultAuthenticationResponseAuditExtractors')}" />
-
+ p:fieldExtractors="#{getObject('shibboleth.oidc.rp.PostRequestAuditExtractors') ?: getObject('shibboleth.oidc.rp.DefaultPostRequestAuditExtractors')}" />
+
<bean id="WriteAuditLog" class="net.shibboleth.idp.profile.audit.impl.WriteAuditLog" scope="prototype"
p:profileContextLookupStrategy-ref="shibboleth.ChildLookup.ProxyProfileRequestContext"
p:formattingMap-ref="shibboleth.AuditFormattingMap"
@@ -348,6 +344,11 @@
</property>
</bean>
+ <bean id="AuthenticationResponsePopulateAuditContext" parent="shibboleth.AbstractPopulateAuditContext"
+ p:profileContextLookupStrategy-ref="shibboleth.ChildLookup.ProxyProfileRequestContext"
+ p:fieldExtractors="#{getObject('shibboleth.oidc.rp.AuthenticationResponseAuditExtractors') ?: getObject('shibboleth.oidc.rp.DefaultAuthenticationResponseAuditExtractors')}" />
+
+
<bean id="IsCodeFlow" class="net.shibboleth.idp.plugin.authn.oidc.rp.config.logic.IsCodeFlowPredicate"/>
<bean id="IsHybridFlow" class="net.shibboleth.idp.plugin.authn.oidc.rp.config.logic.IsHybridFlowPredicate"/>
<bean id="IsImplicitFlow" class="net.shibboleth.idp.plugin.authn.oidc.rp.config.logic.IsImplicitFlowPredicate"/>
@@ -537,10 +538,7 @@
p:claimsValidator="#{getObject('shibboleth.authn.oidc.rp.idtoken.IDTokenClaimsValidator')
?: getObject('DefaultIDTokenClaimsValidator')}"
p:jwtLookupStrategy="#{getObject('shibboleth.authn.oidc.rp.idtoken.IDTokenLookupStrategy')
- ?: getObject('DefaultIDTokenLookupStrategy')}" />
-
- <bean id="DefaultIDTokenLookupStrategy"
- class="net.shibboleth.idp.plugin.authn.oidc.rp.impl.DefaultIDTokenLookupStrategy" />
+ ?: getObject('shibboleth.authn.oidc.rp.DefaultIDTokenLookupStrategy')}" />
<bean id="DefaultIDTokenClaimsValidator"
class="net.shibboleth.oidc.security.jwt.claims.impl.ChainingJWTClaimsValidator"
@@ -761,6 +759,8 @@
</constructor-arg>
</bean>
+ <bean id="shibboleth.authn.oidc.rp.DefaultUserInfoTokenLookupStrategy"
+ class="net.shibboleth.idp.plugin.authn.oidc.rp.impl.DefaultUserInfoTokenLookupStrategy" />
<bean id="ValidateUserInfoTokenClaims" scope="prototype"
class="net.shibboleth.idp.plugin.authn.oidc.rp.impl.ValidateTokenClaims"
@@ -770,15 +770,13 @@
p:claimsValidator="#{getObject('shibboleth.authn.oidc.rp.userinfo.UserInfoTokenClaimsValidator')
?: getObject('DefaultUserInfoTokenClaimsValidator')}"
p:jwtLookupStrategy="#{getObject('shibboleth.authn.oidc.rp.userinfo.UserInfoTokenLookupStrategy')
- ?: getObject('DefaultUserInfoTokenLookupStrategy')}" />
+ ?: getObject('shibboleth.authn.oidc.rp.DefaultUserInfoTokenLookupStrategy')}" />
<bean id="DefaultUserInfoTokenClaimsValidator"
class="net.shibboleth.oidc.security.jwt.claims.impl.ChainingJWTClaimsValidator"
p:claimValidators-ref="UserInfoClaimsValidators" />
- <bean id="DefaultUserInfoTokenLookupStrategy"
- class="net.shibboleth.idp.plugin.authn.oidc.rp.impl.DefaultUserInfoTokenLookupStrategy" />
-
+
<bean id="UserInfoTokenRequiredClaimsValidator"
class="net.shibboleth.oidc.security.jwt.claims.impl.RequiredClaimsValidator">
<property name="requiredClaims">
@@ -802,11 +800,6 @@
<ref bean="AudienceClaimsValidator" />
</util:list>
- <bean id="UserInfoResponsePopulateAuditContext" parent="shibboleth.AbstractPopulateAuditContext"
- p:profileContextLookupStrategy-ref="shibboleth.ChildLookup.ProxyProfileRequestContext"
- p:fieldExtractors="#{getObject('shibboleth.oidc.rp.UserInfoResponseAuditExtractors') ?: getObject('shibboleth.oidc.rp.DefaultUserInfoResponseAuditExtractors')}" />
-
-
<!-- This is a very simplified and hard coded version of the claims verification used for a JWT. Maybe look to replace -->
<bean id="ValidateUserInfoPlainResponseClaims" scope="prototype"
class="net.shibboleth.idp.plugin.authn.oidc.rp.impl.ValidateUserInfoJSONObjectClaims"
@@ -817,8 +810,11 @@
<bean id="ProcessEndUserClaims" class="net.shibboleth.idp.plugin.authn.oidc.rp.impl.ProcessEndUserClaims"
scope="prototype" p:profileContextLookupStrategy-ref="shibboleth.ChildLookup.ProxyProfileRequestContext"
p:authenticationContextLookupStrategy-ref="ParentAuthenticiationContextLookup" />
-
-
+
+ <bean id="PostResponsePopulateAuditContext" parent="shibboleth.AbstractPopulateAuditContext"
+ p:profileContextLookupStrategy-ref="shibboleth.ChildLookup.ProxyProfileRequestContext"
+ p:fieldExtractors="#{getObject('shibboleth.oidc.rp.PostResponseAuditExtractors') ?: getObject('shibboleth.oidc.rp.DefaultPostResponseAuditExtractors')}" />
+
<bean id="CheckUserInfoPlainResponseTypeCondition"
class="net.shibboleth.idp.plugin.authn.oidc.rp.messaging.context.logic.UserInfoPlainResponseTypeCondition" />
@@ -834,6 +830,7 @@
p:attributeFilter-ref="shibboleth.AttributeFilterService"
p:transcoderRegistry-ref="shibboleth.AttributeRegistryService" />
+ <bean id="UnsupportedResponseTypeAction" class="net.shibboleth.idp.plugin.authn.oidc.rp.impl.UnsupportedResponseTypeAction"/>
<!-- Can override one or more of the beans above. Note, the property override is mostly to allow tests
to change the location of the user config file. -->
diff --git a/idp-oidc-rp-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/authn/OIDCRelyingParty/oidc-relying-party-authn-flow.xml b/idp-oidc-rp-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/authn/OIDCRelyingParty/oidc-relying-party-authn-flow.xml
index 84aa7f9..e5a7ef3 100644
--- a/idp-oidc-rp-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/authn/OIDCRelyingParty/oidc-relying-party-authn-flow.xml
+++ b/idp-oidc-rp-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/authn/OIDCRelyingParty/oidc-relying-party-authn-flow.xml
@@ -6,7 +6,7 @@
<!-- This is a login flow for proxied authentication implemented via OIDC -->
- <!-- OP discovery? -->
+ <!-- OP discovery e.g. webfinger -->
<on-start>
<!-- If installed, this can bypass discovery. -->
<evaluate
@@ -30,11 +30,12 @@
<evaluate expression="OIDCProviderMetadataLookup" />
<evaluate expression="InitializeRelyingPartyContext" />
<evaluate expression="SelectRelyingPartyConfiguration" />
-
<evaluate expression="PostLookupPopulateAuditContext" />
+
<evaluate expression="InitializeOutboundMessageContext" />
<evaluate expression="SelectProfileConfiguration" />
<evaluate expression="InitializeOAuth2ClientContext" />
+
<evaluate expression="InitializeAuthorizationRequest" />
<evaluate expression="AddResponseTypeAndMode" />
<evaluate expression="AddScopes" />
@@ -43,16 +44,16 @@
<evaluate expression="AddEndpointURI" />
<evaluate expression="AddRequestedClaims" />
<evaluate expression="AddRedirectURI"/>
- <evaluate expression="AddAuthenticationContextClassReferences" />
+ <evaluate expression="AddAuthenticationContextClassReferences" />
<evaluate expression="PostRequestPopulateAuditContext" />
+
<evaluate expression="WriteAuditLog" />
<!-- <evaluate expression="InitializeMessageChannelSecurityContext" /> -->
<evaluate expression="'proceed'" />
-
<transition on="proceed" to="RequestObjectRequiredAndSupported" />
</action-state>
- <!-- Is a request object required by the config, and does the OP support it? -->
+ <!-- Is a request object required by the configuration, and does the OP support it? -->
<decision-state id="RequestObjectRequiredAndSupported">
<if test="RequestObjectRequiredAndSupportedPredicate.test(ProxyProfileRequestContextLookup.apply(opensamlProfileRequestContext))"
then="BuildRequestObject"
@@ -63,7 +64,10 @@
<evaluate expression="PopulateRequestObjectSignatureSigningParameters" />
<evaluate expression="PopulateRequestObjectEncryptionParameters" />
<evaluate expression="BuildRequestObject" />
- <!-- We can not sign and encrypt the RO here. That is left to the preEncodeMessageHandlers. -->
+ <!--
+ We can not sign and encrypt the RO here (we need state from WF execution key).
+ That is left to the preEncodeMessageHandlers.
+ -->
<evaluate expression="'proceed'" />
<transition on="proceed" to="AuthnRequest" />
</action-state>
@@ -82,7 +86,10 @@
<transition to="ValidateResponse" />
</view-state>
- <!-- Generally validate the response, in a way that is agnostic to the grant_type -->
+ <!--
+ Generally validate the response in a way that is agnostic to the
+ response_type and authentication flow used.
+ -->
<action-state id="ValidateResponse">
<evaluate expression="ValidateExternalAuthenticationContext" />
<evaluate expression="AuthenticationResponsePopulateAuditContext" />
@@ -94,24 +101,24 @@
id_token matched against the original provider metadata).
-->
<evaluate expression="AddPeerEntityContextToInboundMessage" />
- <evaluate expression="'proceed'" />
- <transition on="proceed" to="SwitchOnGrantType" />
- <on-exit>
- <evaluate expression="WriteAuditLog" />
- </on-exit>
+ <evaluate expression="'proceed'" />
+ <transition on="proceed" to="SwitchOnAuthenticationFlowType" />
</action-state>
- <!-- Switch flow path based on OIDC grant_type used. Only code flow is actually supported currently. -->
- <decision-state id="SwitchOnGrantType">
+ <!--
+ Switch webflow path based on the implied OIDC authentication flow taken from the response_type used.
+ Only the 'code' response_type and hence Authorization/Authentication Code Flow is actually supported.
+ -->
+ <decision-state id="SwitchOnAuthenticationFlowType">
<if test="IsCodeFlow.test(OutboundMessageContextFromRootPRC.apply(opensamlProfileRequestContext))"
- then="CodeFlow" />
+ then="AuthorizationCodeFlow" />
<if test="IsHybridFlow.test(OutboundMessageContextFromRootPRC.apply(opensamlProfileRequestContext))"
then="HybridFlow" />
<if test="IsImplicitFlow.test(OutboundMessageContextFromRootPRC.apply(opensamlProfileRequestContext))"
then="ImplicitFlow" else="UnsupportedFlow" />
</decision-state>
- <action-state id="CodeFlow">
+ <action-state id="AuthorizationCodeFlow">
<evaluate expression="InitializeOAuth2ClientAuthenticationContext" />
<evaluate expression="ExchangeCodeForAccessToken" />
<evaluate expression="ValidateOAuthAccessTokenResponse" />
@@ -125,21 +132,17 @@
<evaluate expression="TokenResponsePopulateAuditContext" />
<evaluate expression="'proceed'" />
<transition on="proceed" to="CheckUserInfoClaimsRequired" />
- <on-exit>
- <evaluate expression="WriteAuditLog" />
- </on-exit>
</action-state>
-
+ <!-- Should we use the access_token to request UserInfo claims? -->
<decision-state id="CheckUserInfoClaimsRequired">
<if test="CheckUserInfoRequiredCondition.test(ProxyProfileRequestContextLookup.apply(opensamlProfileRequestContext))"
then="UserInfoRequest" else="FinalizeResponse" />
- <!-- if else here, we need to set id_token claims into EndUserClaimsContext -->
</decision-state>
<action-state id="UserInfoRequest">
<evaluate expression="UserInfoEndpointLookup" />
- <!-- Something needs to check TLS server certificate? -->
+ <!-- Something needs to check TLS server certificate? Not sure, performed by HTTP Client -->
<evaluate expression="'proceed'" />
<transition on="proceed" to="CheckUserInfoResponseType" />
</action-state>
@@ -157,34 +160,31 @@
<evaluate expression="PopulateUserInfoTokenSignatureValidationParameters" />
<evaluate expression="HandleUserInfoTokenValidation" />
<evaluate expression="ValidateUserInfoTokenClaims" />
- <evaluate expression="UserInfoResponsePopulateAuditContext" />
<evaluate expression="'proceed'" />
<transition on="proceed" to="FinalizeResponse" />
- <on-exit>
- <evaluate expression="WriteAuditLog" />
- </on-exit>
</action-state>
<!-- Plain UserInfo response types will skip straight to this stage -->
<action-state id="ValidateUserInfoPlainClaimsSet">
<evaluate expression="ValidateUserInfoPlainResponseClaims" />
- <evaluate expression="UserInfoResponsePopulateAuditContext" />
<evaluate expression="'proceed'" />
<transition on="proceed" to="FinalizeResponse" />
- <on-exit>
- <evaluate expression="WriteAuditLog" />
- </on-exit>
</action-state>
<action-state id="FinalizeResponse">
- <evaluate expression="ProcessEndUserClaims" />
+ <evaluate expression="ProcessEndUserClaims" />
+ <evaluate expression="PostResponsePopulateAuditContext" />
<evaluate expression="ValidateOIDCAuthentication" />
- <evaluate expression="'proceed'" />
+ <evaluate expression="WriteAuditLog" />
+ <evaluate expression="'proceed'" />
<!-- Subject canonicalization -->
- <transition on="proceed" to="proceed" />
+ <transition on="proceed" to="proceed" />
</action-state>
- <!-- Placeholders for flows which are not supported, and would not work without some front-end impl. -->
+ <!--
+ Placeholders for flows which are not supported, and would not work without some front-end JavaScript
+ pulling out authentication response parameters from URL fragments and sending to the callback endpoint.
+ -->
<action-state id="HybridFlow">
<evaluate expression="'proceed'" />
<transition on="proceed" to="UnsupportedFlow" />
@@ -195,12 +195,18 @@
<transition on="proceed" to="UnsupportedFlow" />
</action-state>
- <action-state id="UnsupportedFlow">
+ <action-state id="UnsupportedFlow">
+ <evaluate expression="UnsupportedResponseTypeAction"/>
+ <!--
+ It should never get to the below transition, the above action creates an error
+ event that should be caught by the global transition
+ -->
<evaluate expression="'proceed'" />
- <transition on="proceed" to="END" />
+ <transition on="proceed" to="ReselectFlow" />
</action-state>
- <!-- <subflow-state id="CallSubjectCanonicalization" subflow="c14n">
+
+ <!-- <subflow-state id="CallSubjectCanonicalization" subflow="c14n">
<input name="calledAsSubflow" value="true" />
<transition on="proceed" to="proceed" />
@@ -208,6 +214,16 @@
<transition on="SubjectCanonicalizationError" to="ReselectFlow" />
</subflow-state> -->
+ <global-transitions>
+ <!-- Route everything out as a graceful failure to allow subsequent options to run. -->
+ <transition on="#{!'proceed'.equals(currentEvent.id)}" to="ReselectFlow">
+ <evaluate expression="T(org.opensaml.core.metrics.MetricsSupport).getMetricRegistry().counter('net.shibboleth.idp.authn.oidc.rp.failures').inc()" />
+ <evaluate expression="WriteAuditLog" />
+ </transition>
+ </global-transitions>
+
+
+
<bean-import resource="oidc-relying-party-authn-beans.xml" />
</flow>
diff --git a/idp-oidc-rp-impl/src/test/java/net/shibboleth/idp/plugin/authn/oidc/rp/audit/impl/ProxyAuthenticationFlowAuditExtractor.java b/idp-oidc-rp-impl/src/test/java/net/shibboleth/idp/plugin/authn/oidc/rp/audit/impl/ProxyAuthenticationFlowAuditExtractor.java
new file mode 100644
index 0000000..1845949
--- /dev/null
+++ b/idp-oidc-rp-impl/src/test/java/net/shibboleth/idp/plugin/authn/oidc/rp/audit/impl/ProxyAuthenticationFlowAuditExtractor.java
@@ -0,0 +1,51 @@
+/*
+ * Licensed to the University Corporation for Advanced Internet Development,
+ * Inc. (UCAID) under one or more contributor license agreements. See the
+ * NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The UCAID licenses this file to You under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.shibboleth.idp.plugin.authn.oidc.rp.audit.impl;
+
+import java.util.function.Function;
+
+import javax.annotation.Nullable;
+
+import org.opensaml.messaging.context.BaseContext;
+import org.opensaml.profile.context.ProfileRequestContext;
+
+import net.shibboleth.idp.authn.context.AuthenticationContext;
+
+/**
+ * {@link Function} that returns the authentication flow ID from the attempted flow of the
+ * parent context used to satisfy a request. Assuming the parent is an {@link AuthenticationContext}
+ * as is the case in a proxy request.
+ */
+public class ProxyAuthenticationFlowAuditExtractor implements Function<ProfileRequestContext,String> {
+
+ /** {@inheritDoc} */
+ @Override
+ @Nullable public String apply(@Nullable final ProfileRequestContext input) {
+
+ final BaseContext baseContext = input.getParent();
+ if (baseContext instanceof AuthenticationContext) {
+ final AuthenticationContext authnCtx = (AuthenticationContext)baseContext;
+ if (authnCtx != null && authnCtx.getAttemptedFlow()!= null) {
+ return authnCtx.getAttemptedFlow().getId();
+ }
+ }
+
+ return null;
+ }
+
+}
diff --git a/idp-oidc-rp-impl/src/test/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/OIDCRPFlowTest.java b/idp-oidc-rp-impl/src/test/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/OIDCRPFlowTest.java
index 135ba3c..0fa1ed2 100644
--- a/idp-oidc-rp-impl/src/test/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/OIDCRPFlowTest.java
+++ b/idp-oidc-rp-impl/src/test/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/OIDCRPFlowTest.java
@@ -36,6 +36,7 @@ import org.apache.http.ssl.SSLContextBuilder;
import org.junit.Test;
import org.mockito.Mockito;
import org.opensaml.core.config.InitializationException;
+import org.opensaml.core.metrics.impl.MetricRegistryInitializer;
import org.opensaml.messaging.context.MessageContext;
import org.opensaml.profile.context.ProfileRequestContext;
import org.opensaml.security.credential.Credential;
@@ -72,6 +73,7 @@ import net.shibboleth.idp.authn.context.RequestedPrincipalContext;
import net.shibboleth.idp.authn.context.SubjectCanonicalizationContext;
import net.shibboleth.idp.authn.impl.ExternalAuthenticationImpl;
import net.shibboleth.idp.authn.principal.UsernamePrincipal;
+import net.shibboleth.idp.plugin.authn.oidc.rp.context.EndUserClaimsContext;
import net.shibboleth.idp.plugin.authn.oidc.rp.context.OAuth2ClientContext;
import net.shibboleth.idp.plugin.authn.oidc.rp.context.OIDCPeerEntityContext;
import net.shibboleth.idp.plugin.authn.test.flow.AbstractAuthnXmlFlowExecutionTests;
@@ -246,11 +248,7 @@ public class OIDCRPFlowTest extends AbstractAuthnXmlFlowExecutionTests {
addBeanDefinition(builderContext, "shibboleth.DefaultFlowStartAuditExtractors",BeanDefinitionBuilder.
genericBeanDefinition(HashMap.class).getBeanDefinition());
-
- addBeanDefinition(builderContext, "shibboleth.AbstractPopulateAuditContext",BeanDefinitionBuilder.
- genericBeanDefinition(net.shibboleth.idp.profile.audit.impl.PopulateAuditContext.class)
- .setAbstract(true).getBeanDefinition());
-
+
addBeanDefinition(builderContext, "shibboleth.PropertySourcesPlaceholderConfigurer",BeanDefinitionBuilder.
genericBeanDefinition(org.springframework.context.support.PropertySourcesPlaceholderConfigurer.class)
@@ -299,10 +297,23 @@ public class OIDCRPFlowTest extends AbstractAuthnXmlFlowExecutionTests {
log.error("Could not initialise the algorithm registry");
fail();
}
+
+
+ try {
+ final MetricRegistryInitializer metricInit = new MetricRegistryInitializer();
+ metricInit.init();
+ } catch (final InitializationException e) {
+ log.error("Could not initialise the metric registry");
+ fail();
+ }
+
+ // The audit system beans
+ loadBeanDefinitionsFromXmlFile(builderContext,
+ new ClassPathResource("conf/audit.xml"), null);
loadBeanDefinitionsFromXmlFile(builderContext,
new ClassPathResource("META-INF/net.shibboleth.idp/postconfig.xml"),
- null);
+ null);
// Note, is the relying-party which loads the profile config in the postconfig.
// So properties for the profile config need to go here.
@@ -318,7 +329,7 @@ public class OIDCRPFlowTest extends AbstractAuthnXmlFlowExecutionTests {
new ClassPathResource("attribute/registry/postconfig.xml"), null);
loadBeanDefinitionsFromXmlFile(builderContext,
- new ClassPathResource("attribute/filter/attribute-filter-system.xml"), null);
+ new ClassPathResource("attribute/filter/attribute-filter-system.xml"), null);
// Add a signing key incase it is used
loadBeanDefinitionsFromXmlFile(builderContext,
@@ -1196,9 +1207,57 @@ public class OIDCRPFlowTest extends AbstractAuthnXmlFlowExecutionTests {
resumeFlow(externalContext);
//assert success conditions
- assertFlowExecutionEnded();
+ // will end on ValidateResponse action
+ assertCurrentStateEquals("ValidateResponse");
assertNotNull(prc.getSubcontext(AuthenticationContext.class));
assertNull(prc.getSubcontext(SubjectCanonicalizationContext.class));
}
+
+ /**
+ * Test the flow terminates correctly when an unsupported flow is used - which is unlikely to get
+ * this far.
+ *
+ * @throws Exception on error.
+ */
+ @Test
+ public void testAuthnFlowFromAuthorizationCallback_UnsupportedOIDCFlow()
+ throws Exception {
+
+ setFlowPath(FLOW);
+ setFlowModelResources(flowResources);
+ setSubflows(subflows);
+
+ final Map<String,String> mockProperties = Map.of(
+ "idp.entityID", "http://idp.example.com/",
+ "idp.authn.oidc.rp.proxyIssuer",OP_ISSUER_ID);
+
+ setMockProperties(mockProperties);
+
+ final var flowExecution = (FlowExecutionImpl)getFlowExecutionFactory()
+ .createFlowExecution(getFlowDefinition());
+
+ final ProfileRequestContext prc = populateBasicContextTreeFromAuthnResponse(flowExecution);
+
+ // Add a response type that suggests this flow was triggered by the IMPLICIT grant.
+ final OIDCAuthenticationRequest request =
+ (OIDCAuthenticationRequest)prc.getSubcontext(AuthenticationContext.class)
+ .getSubcontext(ProfileRequestContext.class).getOutboundMessageContext().getMessage();
+
+ request.setResponseType(ResponseType.IDTOKEN);
+
+ assertNotNull(request);
+ updateFlowExecution(flowExecution);
+
+ //set start view and ending event to transition on.
+ externalContext.setEventId("proceed");
+ setCurrentState("AuthnRequest");
+ resumeFlow(externalContext);
+
+ assertFlowExecutionEnded();
+ // Flow did not produce an end-user message context
+ assertNull(prc.getSubcontext(AuthenticationContext.class).getSubcontext(ProfileRequestContext.class)
+ .getInboundMessageContext().getSubcontext(EndUserClaimsContext.class));
+
+ }
}
diff --git a/idp-oidc-rp-impl/src/test/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/TestTokenHelper.java b/idp-oidc-rp-impl/src/test/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/TestTokenHelper.java
index 5be9ef2..445ff07 100644
--- a/idp-oidc-rp-impl/src/test/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/TestTokenHelper.java
+++ b/idp-oidc-rp-impl/src/test/java/net/shibboleth/idp/plugin/authn/oidc/rp/impl/TestTokenHelper.java
@@ -82,6 +82,7 @@ public final class TestTokenHelper {
.claim("nonce", nonce)
.claim("azp", clientId)
.claim("name",name)
+ .claim("auth_time", new Date())
.issueTime(new Date())
.expirationTime(Date.from(Instant.now().plusSeconds(120)))
.build();
diff --git a/idp-oidc-rp-impl/src/test/java/net/shibboleth/idp/plugin/authn/test/flow/AbstractAuthnXmlFlowExecutionTests.java b/idp-oidc-rp-impl/src/test/java/net/shibboleth/idp/plugin/authn/test/flow/AbstractAuthnXmlFlowExecutionTests.java
index f894e65..76055dc 100644
--- a/idp-oidc-rp-impl/src/test/java/net/shibboleth/idp/plugin/authn/test/flow/AbstractAuthnXmlFlowExecutionTests.java
+++ b/idp-oidc-rp-impl/src/test/java/net/shibboleth/idp/plugin/authn/test/flow/AbstractAuthnXmlFlowExecutionTests.java
@@ -372,6 +372,9 @@ public abstract class AbstractAuthnXmlFlowExecutionTests extends CustomAbstractX
.setParentName("shibboleth.Functions.Compose")
.addConstructorArgReference("shibboleth.Functions.ProxyProfileRequestAuthenticationContext")
.addConstructorArgValue(new WebflowRequestContextProfileRequestContextLookup()).getBeanDefinition());
+
+ // Setup the audit context
+
}
diff --git a/idp-oidc-rp-impl/src/test/resources/conf/audit.xml b/idp-oidc-rp-impl/src/test/resources/conf/audit.xml
new file mode 100644
index 0000000..8c78cb3
--- /dev/null
+++ b/idp-oidc-rp-impl/src/test/resources/conf/audit.xml
@@ -0,0 +1,74 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<beans xmlns="http://www.springframework.org/schema/beans"
+ xmlns:context="http://www.springframework.org/schema/context"
+ xmlns:util="http://www.springframework.org/schema/util" xmlns:p="http://www.springframework.org/schema/p"
+ xmlns:c="http://www.springframework.org/schema/c" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
+ http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
+ http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd"
+
+ default-init-method="initialize"
+ default-destroy-method="destroy">
+
+ <!-- COPIED FROM THE MAIN IDP-CONF TO INIT THE AUDIT SYSTEM, ALSO CONTAINS BEANS FROM ELSEWHERE -->
+
+ <bean id="shibboleth.AbstractPopulateAuditContext" abstract="true"
+ class="net.shibboleth.idp.profile.audit.impl.PopulateAuditContext" scope="prototype"
+ p:formattingMapParser-ref="shibboleth.AuditFormattingMapParser"
+ p:dateTimeFormat="#{getObject('shibboleth.AuditDateTimeFormat')}"
+ p:useDefaultTimeZone="#{getObject('shibboleth.AuditDefaultTimeZone') ?: false}"
+ p:fieldReplacements="#{getObject('shibboleth.AuditFieldReplacementMap')}" />
+
+ <bean id="shibboleth.AuditFormattingMapParser"
+ class="net.shibboleth.idp.profile.audit.impl.PopulateAuditContext.FormattingMapParser"
+ c:_0-ref="shibboleth.AuditFormattingMap" />
+
+
+ <!--
+ This bean defines a mapping between audit log categories and formatting strings.
+ -->
+ <!-- <util:map id="shibboleth.AuditFormattingMap">
+ <entry key="Shibboleth-Audit" value="%a|%ST|%T|%u|%SP|%i|%ac|%t|%attr|%n|%f|%SSO|%XX|%XA|%b|%bb|%e|%S|%SS|%s|%UA" />
+ </util:map> -->
+
+ <!-- This is not the default logging format in a normal install! -->
+ <util:map id="shibboleth.AuditFormattingMap">
+ <entry key="Shibboleth-Audit" value="%a|%ST|%T|%u|%SP|%i|%ac|%AF|%t|%attr|%n|%f|%SSO|%XX|%XA|%b|%bb|%e|%S|%SS|%s|%UA|%DEST|%RS|%RDURI|%fauth|%RESPT|%RESPM|%scope|%ACRS|%AUTHZR|%aud|%t|%SUBUI" />
+ </util:map>
+
+ <!-- Override the format of date/time fields in the log and/or convert to default time zone. -->
+ <!--
+ <bean id="shibboleth.AuditDateTimeFormat" class="java.lang.String" c:_0="yyyy-MM-dd'T'HH:mm:ss.SSSZZ" />
+ <util:constant id="shibboleth.AuditDefaultTimeZone" static-field="java.lang.Boolean.TRUE" />
+ -->
+
+ <!-- Allows auditing to be disabled selectively for particular profiles/flows. -->
+ <util:list id="shibboleth.AuditSuppressedProfiles">
+ <value>http://shibboleth.net/ns/profiles/status</value>
+ <value>http://shibboleth.net/ns/profiles/mdquery</value>
+ </util:list>
+
+ <!--
+ You can freely add/change this map to map constants or frequently appearing strings into
+ shorter values in the audit log.
+ -->
+ <util:map id="shibboleth.AuditFieldReplacementMap">
+ <entry key="urn:oasis:names:tc:SAML:1.0:am:password" value="password" />
+ <entry key="urn:oasis:names:tc:SAML:2.0:ac:classes:Password" value="password" />
+ <entry key="urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport" value="password" />
+ <entry key="urn:mace:shibboleth:1.0:nameIdentifier" value="transient" />
+ <entry key="urn:oasis:names:tc:SAML:2.0:nameid-format:transient" value="transient" />
+ <entry key="urn:oasis:names:tc:SAML:2.0:nameid-format:persistent" value="persistent" />
+ <entry key="urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress" value="emailAddress" />
+ <entry key="urn:oasis:names:tc:SAML:2.0:status:Success" value="Success" />
+ <entry key="urn:oasis:names:tc:SAML:2.0:status:Requester" value="Requester" />
+ <entry key="urn:oasis:names:tc:SAML:2.0:status:Responder" value="Responder" />
+ <entry key="http://www.w3.org/2009/xmlenc11#aes128-gcm" value="AES128-GCM" />
+ <entry key="http://www.w3.org/2009/xmlenc11#aes192-gcm" value="AES192-GCM" />
+ <entry key="http://www.w3.org/2009/xmlenc11#aes256-gcm" value="AES256-GCM" />
+ <entry key="http://www.w3.org/2001/04/xmlenc#aes128-cbc" value="AES128-CBC" />
+ <entry key="http://www.w3.org/2001/04/xmlenc#aes192-cbc" value="AES192-CBC" />
+ <entry key="http://www.w3.org/2001/04/xmlenc#aes256-cbc" value="AES256-CBC" />
+ </util:map>
+
+</beans>
diff --git a/idp-oidc-rp-impl/src/test/resources/logback-test.xml b/idp-oidc-rp-impl/src/test/resources/logback-test.xml
index 2e54ae8..8efbe68 100644
--- a/idp-oidc-rp-impl/src/test/resources/logback-test.xml
+++ b/idp-oidc-rp-impl/src/test/resources/logback-test.xml
@@ -6,7 +6,9 @@
<logger name="net.shibboleth.idp.plugin.authn" level="TRACE"/>
<logger name="org.springframework" level="INFO"/>
<logger name="org.opensaml.xmlsec.config.GlobalAlgorithmRegistryInitializer" level="DEBUG"/>
- <logger name="org.opensaml.xmlsec.algorithm" level="DEBUG"/>
+ <logger name="org.opensaml.xmlsec.algorithm" level="DEBUG"/>
+ <logger name="net.shibboleth.idp.profile.audit.impl" level="TRACE"/>
+
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>%level [%logger:%line] - %msg%n</pattern>
@@ -19,4 +21,8 @@
<appender-ref ref="STDOUT" />
</root>
+ <logger name="Shibboleth-Audit" level="ALL">
+
+ </logger>
+
</configuration>
\ No newline at end of file
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
More information about the commits
mailing list