[java-idp-plugin-totp] branch main updated: JTOTP-8/9 - Full 5.0 port and CSP additions.
Scott Cantor
cantor.2 at osu.edu
Thu Oct 26 16:51:18 UTC 2023
This is an automated email from the git hooks/post-receive script.
scantor pushed a commit to branch main
in repository java-idp-plugin-totp.
View the commit online:
http://git.shibboleth.net/view/?p=java-idp-plugin-totp.git;a=commit;h=062d3aa334ca9a4146d3806fe1a7df46a2ec225f
The following commit(s) were added to refs/heads/main by this push:
new 062d3aa JTOTP-8/9 - Full 5.0 port and CSP additions.
062d3aa is described below
commit 062d3aa334ca9a4146d3806fe1a7df46a2ec225f
Author: Scott Cantor <cantor.2 at osu.edu>
AuthorDate: Thu Oct 26 12:51:15 2023 -0400
JTOTP-8/9 - Full 5.0 port and CSP additions.
https://shibboleth.atlassian.net/browse/JTOTP-8
https://shibboleth.atlassian.net/browse/JTOTP-9
Null cleanup as well.
---
.../idp/plugin/authn/totp/TOTPPlugin.java | 6 ++--
.../totp/impl/AbstractTOTPExtractionAction.java | 13 ++++---
.../totp/impl/AttributeResolverSeedSource.java | 5 +--
.../totp/impl/ExtractTOTPFromFormRequest.java | 6 ----
.../authn/totp/impl/ExtractTOTPFromHeader.java | 6 ----
.../authn/totp/impl/GoogleTOTPAuthenticator.java | 12 ++-----
.../totp/impl/TOTPAuthenticatorArguments.java | 3 +-
.../authn/totp/impl/TOTPAuthenticatorCLI.java | 17 +++++----
.../authn/totp/impl/TOTPCredentialValidator.java | 11 ++++--
.../idp/flows/authn/TOTP/TOTP-authenticator.xml | 3 --
.../shibboleth/idp/flows/authn/TOTP/TOTP-beans.xml | 40 +++++++++++++++-------
.../shibboleth/idp/flows/authn/TOTP/TOTP-flow.xml | 4 ++-
.../shibboleth/idp/plugin/authn/totp/views/totp.vm | 7 ++--
.../totp/impl/AttributeResolverSeedSourceTest.java | 8 ++---
.../totp/impl/ExtractTOTPFromFormRequestTest.java | 16 ++++++---
.../authn/totp/impl/ExtractTOTPFromHeaderTest.java | 16 ++++++---
.../totp/impl/GoogleTOTPAuthenticatorTest.java | 28 ++++++++-------
17 files changed, 116 insertions(+), 85 deletions(-)
diff --git a/totp-impl/src/main/java/net/shibboleth/idp/plugin/authn/totp/TOTPPlugin.java b/totp-impl/src/main/java/net/shibboleth/idp/plugin/authn/totp/TOTPPlugin.java
index 2627f91..0309a4b 100644
--- a/totp-impl/src/main/java/net/shibboleth/idp/plugin/authn/totp/TOTPPlugin.java
+++ b/totp-impl/src/main/java/net/shibboleth/idp/plugin/authn/totp/TOTPPlugin.java
@@ -15,12 +15,12 @@
package net.shibboleth.idp.plugin.authn.totp;
import java.io.IOException;
-import java.util.Collections;
import net.shibboleth.idp.module.IdPModule;
import net.shibboleth.idp.plugin.impl.FirstPartyIdPPlugin;
import net.shibboleth.profile.module.ModuleException;
import net.shibboleth.profile.plugin.PluginException;
+import net.shibboleth.shared.collection.CollectionSupport;
/**
* Details about the TOTP login plugin.
@@ -37,8 +37,8 @@ public class TOTPPlugin extends FirstPartyIdPPlugin {
super(TOTPPlugin.class);
try {
final IdPModule module = new TOTPModule();
- setEnableOnInstall(Collections.singleton(module));
- setDisableOnRemoval(Collections.singleton(module));
+ setEnableOnInstall(CollectionSupport.singleton(module));
+ setDisableOnRemoval(CollectionSupport.singleton(module));
} catch (final IOException e) {
throw e;
} catch (final ModuleException e) {
diff --git a/totp-impl/src/main/java/net/shibboleth/idp/plugin/authn/totp/impl/AbstractTOTPExtractionAction.java b/totp-impl/src/main/java/net/shibboleth/idp/plugin/authn/totp/impl/AbstractTOTPExtractionAction.java
index 762eace..af2d23d 100644
--- a/totp-impl/src/main/java/net/shibboleth/idp/plugin/authn/totp/impl/AbstractTOTPExtractionAction.java
+++ b/totp-impl/src/main/java/net/shibboleth/idp/plugin/authn/totp/impl/AbstractTOTPExtractionAction.java
@@ -30,6 +30,7 @@ import net.shibboleth.shared.primitive.LoggerFactory;
import org.opensaml.messaging.context.navigate.ChildContextLookup;
import org.opensaml.profile.action.ActionSupport;
+import org.opensaml.profile.action.EventIds;
import org.opensaml.profile.context.ProfileRequestContext;
import org.slf4j.Logger;
@@ -58,9 +59,6 @@ public abstract class AbstractTOTPExtractionAction extends AbstractAuthenticatio
/** Creation strategy for TOTP context. */
@Nonnull private Function<AuthenticationContext,TOTPContext> totpContextCreationStrategy;
- /** TOTP context being operated on. */
- @Nullable private TOTPContext totpContext;
-
/** Constructor. */
public AbstractTOTPExtractionAction() {
usernameLookupStrategy = new CanonicalUsernameLookupStrategy();
@@ -97,7 +95,14 @@ public abstract class AbstractTOTPExtractionAction extends AbstractAuthenticatio
// Clear error state.
authenticationContext.removeSubcontext(AuthenticationErrorContext.class);
- totpContext = totpContextCreationStrategy.apply(authenticationContext);
+ final TOTPContext totpContext = totpContextCreationStrategy.apply(authenticationContext);
+ if (totpContext == null) {
+ log.warn("{} Unable to create TOTP context", getLogPrefix());
+ ActionSupport.buildEvent(profileRequestContext, EventIds.INVALID_PROFILE_CTX);
+ return;
+ }
+
+
totpContext.setTokenCode(null);
// Fill in username if not set.
diff --git a/totp-impl/src/main/java/net/shibboleth/idp/plugin/authn/totp/impl/AttributeResolverSeedSource.java b/totp-impl/src/main/java/net/shibboleth/idp/plugin/authn/totp/impl/AttributeResolverSeedSource.java
index 70627b4..3e6ed0a 100644
--- a/totp-impl/src/main/java/net/shibboleth/idp/plugin/authn/totp/impl/AttributeResolverSeedSource.java
+++ b/totp-impl/src/main/java/net/shibboleth/idp/plugin/authn/totp/impl/AttributeResolverSeedSource.java
@@ -15,7 +15,6 @@
package net.shibboleth.idp.plugin.authn.totp.impl;
import java.util.Collection;
-import java.util.Collections;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
@@ -34,6 +33,7 @@ import net.shibboleth.shared.annotation.constraint.ThreadSafeAfterInit;
import net.shibboleth.shared.codec.Base32Support;
import net.shibboleth.shared.codec.Base64Support;
import net.shibboleth.shared.codec.DecodingException;
+import net.shibboleth.shared.collection.CollectionSupport;
import net.shibboleth.shared.component.ComponentInitializationException;
import net.shibboleth.shared.logic.Constraint;
import net.shibboleth.shared.primitive.LoggerFactory;
@@ -102,7 +102,7 @@ public class AttributeResolverSeedSource extends AbstractSeedSource {
resCtx.setResolutionLabel("TOTP");
resCtx.setPrincipal(totp.getUsername());
- resCtx.setRequestedIdPAttributeNames(Collections.singletonList(attributeId));
+ resCtx.setRequestedIdPAttributeNames(CollectionSupport.singletonList(attributeId));
log.debug("Resolving attribute {} for '{}'", attributeId, totp.getUsername());
@@ -120,6 +120,7 @@ public class AttributeResolverSeedSource extends AbstractSeedSource {
.map(StringAttributeValue.class::cast)
.map(StringAttributeValue::getValue)
.forEachOrdered(v -> {
+ assert v != null;
try {
switch (getEncoding()) {
case BASE32:
diff --git a/totp-impl/src/main/java/net/shibboleth/idp/plugin/authn/totp/impl/ExtractTOTPFromFormRequest.java b/totp-impl/src/main/java/net/shibboleth/idp/plugin/authn/totp/impl/ExtractTOTPFromFormRequest.java
index f108def..358a011 100644
--- a/totp-impl/src/main/java/net/shibboleth/idp/plugin/authn/totp/impl/ExtractTOTPFromFormRequest.java
+++ b/totp-impl/src/main/java/net/shibboleth/idp/plugin/authn/totp/impl/ExtractTOTPFromFormRequest.java
@@ -17,13 +17,10 @@ package net.shibboleth.idp.plugin.authn.totp.impl;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
-import org.slf4j.Logger;
-
import jakarta.servlet.http.HttpServletRequest;
import net.shibboleth.shared.annotation.constraint.NonnullAfterInit;
import net.shibboleth.shared.annotation.constraint.NotEmpty;
import net.shibboleth.shared.logic.Constraint;
-import net.shibboleth.shared.primitive.LoggerFactory;
import net.shibboleth.shared.primitive.StringSupport;
/**
@@ -34,9 +31,6 @@ public class ExtractTOTPFromFormRequest extends AbstractTOTPExtractionAction {
/** Default token code field name. */
@Nonnull @NotEmpty public static final String DEFAULT_FIELD_NAME = "tokencode";
- /** Class logger. */
- @Nonnull private final Logger log = LoggerFactory.getLogger(ExtractTOTPFromFormRequest.class);
-
/** Name of header. */
@NonnullAfterInit @NotEmpty private String fieldName;
diff --git a/totp-impl/src/main/java/net/shibboleth/idp/plugin/authn/totp/impl/ExtractTOTPFromHeader.java b/totp-impl/src/main/java/net/shibboleth/idp/plugin/authn/totp/impl/ExtractTOTPFromHeader.java
index 0d1b6b1..15cae81 100644
--- a/totp-impl/src/main/java/net/shibboleth/idp/plugin/authn/totp/impl/ExtractTOTPFromHeader.java
+++ b/totp-impl/src/main/java/net/shibboleth/idp/plugin/authn/totp/impl/ExtractTOTPFromHeader.java
@@ -17,13 +17,10 @@ package net.shibboleth.idp.plugin.authn.totp.impl;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
-import org.slf4j.Logger;
-
import jakarta.servlet.http.HttpServletRequest;
import net.shibboleth.shared.annotation.constraint.NonnullAfterInit;
import net.shibboleth.shared.annotation.constraint.NotEmpty;
import net.shibboleth.shared.logic.Constraint;
-import net.shibboleth.shared.primitive.LoggerFactory;
import net.shibboleth.shared.primitive.StringSupport;
/**
@@ -34,9 +31,6 @@ public class ExtractTOTPFromHeader extends AbstractTOTPExtractionAction {
/** Default token code header. */
@Nonnull @NotEmpty public static final String DEFAULT_HEADER_NAME = "X-Shibboleth-TOTP";
- /** Class logger. */
- @Nonnull private final Logger log = LoggerFactory.getLogger(ExtractTOTPFromHeader.class);
-
/** Name of header. */
@NonnullAfterInit @NotEmpty private String headerName;
diff --git a/totp-impl/src/main/java/net/shibboleth/idp/plugin/authn/totp/impl/GoogleTOTPAuthenticator.java b/totp-impl/src/main/java/net/shibboleth/idp/plugin/authn/totp/impl/GoogleTOTPAuthenticator.java
index 53ca279..3a44734 100644
--- a/totp-impl/src/main/java/net/shibboleth/idp/plugin/authn/totp/impl/GoogleTOTPAuthenticator.java
+++ b/totp-impl/src/main/java/net/shibboleth/idp/plugin/authn/totp/impl/GoogleTOTPAuthenticator.java
@@ -20,8 +20,6 @@ import java.util.Collection;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
-import org.slf4j.Logger;
-
import com.google.common.net.UrlEscapers;
import com.warrenstrange.googleauth.GoogleAuthenticator;
import com.warrenstrange.googleauth.GoogleAuthenticatorConfig;
@@ -37,7 +35,6 @@ import net.shibboleth.shared.codec.EncodingException;
import net.shibboleth.shared.component.AbstractInitializableComponent;
import net.shibboleth.shared.component.ComponentInitializationException;
import net.shibboleth.shared.logic.Constraint;
-import net.shibboleth.shared.primitive.LoggerFactory;
import net.shibboleth.shared.primitive.StringSupport;
/**
@@ -46,9 +43,6 @@ import net.shibboleth.shared.primitive.StringSupport;
@ThreadSafeAfterInit
public class GoogleTOTPAuthenticator extends AbstractInitializableComponent implements TOTPAuthenticator {
- /** Class logger. */
- @Nonnull private final Logger log = LoggerFactory.getLogger(GoogleAuthenticator.class);
-
/** Google Authenticator config. **/
@NonnullAfterInit private GoogleAuthenticatorConfig authconfig;
@@ -105,11 +99,11 @@ public class GoogleTOTPAuthenticator extends AbstractInitializableComponent impl
}
return new TOTPCredential() {
- public byte[] getKey() {
+ @Nonnull public byte[] getKey() {
return secret;
}
- public String getTOTPURL() {
+ @Nonnull public String getTOTPURL() {
final String label;
if (trimmedName != null) {
if (trimmedIssuer != null) {
@@ -133,7 +127,7 @@ public class GoogleTOTPAuthenticator extends AbstractInitializableComponent impl
return url.toString();
}
- public Collection<Integer> getScratchCodes() {
+ @Nonnull public Collection<Integer> getScratchCodes() {
return cred.getScratchCodes();
}
};
diff --git a/totp-impl/src/main/java/net/shibboleth/idp/plugin/authn/totp/impl/TOTPAuthenticatorArguments.java b/totp-impl/src/main/java/net/shibboleth/idp/plugin/authn/totp/impl/TOTPAuthenticatorArguments.java
index 9c302f7..c6b0635 100644
--- a/totp-impl/src/main/java/net/shibboleth/idp/plugin/authn/totp/impl/TOTPAuthenticatorArguments.java
+++ b/totp-impl/src/main/java/net/shibboleth/idp/plugin/authn/totp/impl/TOTPAuthenticatorArguments.java
@@ -63,6 +63,7 @@ public class TOTPAuthenticatorArguments extends AbstractIdPHomeAwareCommandLineA
if (log == null) {
log = LoggerFactory.getLogger(TOTPAuthenticatorArguments.class);
}
+ assert log != null;
return log;
}
@@ -129,7 +130,7 @@ public class TOTPAuthenticatorArguments extends AbstractIdPHomeAwareCommandLineA
}
/** {@inheritDoc} */
- public void printHelp(final PrintStream out) {
+ public void printHelp(@Nonnull final PrintStream out) {
out.println("TOTPAuthenticatorCLI");
out.println("Provides a command line interface for TOTPAuthenticator operations.");
out.println();
diff --git a/totp-impl/src/main/java/net/shibboleth/idp/plugin/authn/totp/impl/TOTPAuthenticatorCLI.java b/totp-impl/src/main/java/net/shibboleth/idp/plugin/authn/totp/impl/TOTPAuthenticatorCLI.java
index 7f9dd74..17c79ec 100644
--- a/totp-impl/src/main/java/net/shibboleth/idp/plugin/authn/totp/impl/TOTPAuthenticatorCLI.java
+++ b/totp-impl/src/main/java/net/shibboleth/idp/plugin/authn/totp/impl/TOTPAuthenticatorCLI.java
@@ -21,7 +21,6 @@ import org.slf4j.Logger;
import com.google.common.net.UrlEscapers;
-import net.shibboleth.idp.Version;
import net.shibboleth.idp.cli.AbstractIdPHomeAwareCommandLine;
import net.shibboleth.idp.plugin.authn.totp.impl.TOTPAuthenticator.TOTPCredential;
import net.shibboleth.shared.annotation.constraint.NotEmpty;
@@ -42,6 +41,7 @@ public class TOTPAuthenticatorCLI extends AbstractIdPHomeAwareCommandLine<TOTPAu
if (log == null) {
log = LoggerFactory.getLogger(TOTPAuthenticatorCLI.class);
}
+ assert log != null;
return log;
}
@@ -54,7 +54,7 @@ public class TOTPAuthenticatorCLI extends AbstractIdPHomeAwareCommandLine<TOTPAu
/** {@inheritDoc} */
@Override
@Nonnull @NotEmpty protected String getVersion() {
- return Version.getVersion();
+ return getClass().getPackage().getImplementationVersion();
}
/** {@inheritDoc} */
@@ -67,15 +67,18 @@ public class TOTPAuthenticatorCLI extends AbstractIdPHomeAwareCommandLine<TOTPAu
try {
final TOTPAuthenticator authenticator;
- if (args.getAuthenticatorName() != null) {
- authenticator = getApplicationContext().getBean(args.getAuthenticatorName(), TOTPAuthenticator.class);
+ final String authenticatorName = args.getAuthenticatorName();
+ if (authenticatorName != null) {
+ authenticator = getApplicationContext().getBean(authenticatorName, TOTPAuthenticator.class);
} else {
authenticator = getApplicationContext().getBean(TOTPAuthenticator.class);
}
- if (args.getSeed() != null && args.getTokenCode() != null) {
-
- if (authenticator.validate(args.getSeed(), args.getTokenCode())) {
+ final byte[] seed = args.getSeed();
+ final Integer tokenCode = args.getTokenCode();
+ if (seed != null && tokenCode != null) {
+
+ if (authenticator.validate(seed, tokenCode)) {
System.out.println("OK");
return RC_OK;
}
diff --git a/totp-impl/src/main/java/net/shibboleth/idp/plugin/authn/totp/impl/TOTPCredentialValidator.java b/totp-impl/src/main/java/net/shibboleth/idp/plugin/authn/totp/impl/TOTPCredentialValidator.java
index b82aadf..ca0353b 100644
--- a/totp-impl/src/main/java/net/shibboleth/idp/plugin/authn/totp/impl/TOTPCredentialValidator.java
+++ b/totp-impl/src/main/java/net/shibboleth/idp/plugin/authn/totp/impl/TOTPCredentialValidator.java
@@ -177,8 +177,11 @@ public class TOTPCredentialValidator extends AbstractCredentialValidator {
log.debug("{} Attempting to authenticate token code for '{}' ", getLogPrefix(), totpContext.getUsername());
try {
+ final Integer tokenCode = totpContext.getTokenCode();
+ // Checked above.
+ assert tokenCode != null;
if (totpContext.getTokenSeeds().stream().anyMatch(
- seed -> authenticator.validate(seed, totpContext.getTokenCode()))) {
+ seed -> authenticator.validate(seed, tokenCode))) {
log.info("{} Login by '{}' succeeded", getLogPrefix(), totpContext.getUsername());
return populateSubject(new Subject(), profileRequestContext, totpContext);
}
@@ -208,7 +211,11 @@ public class TOTPCredentialValidator extends AbstractCredentialValidator {
@Nonnull protected Subject populateSubject(@Nonnull final Subject subject,
@Nonnull final ProfileRequestContext profileRequestContext,
@Nonnull final TOTPContext totpContext) {
- subject.getPrincipals().add(new TOTPPrincipal(totpContext.getUsername()));
+
+ final String username = totpContext.getUsername();
+ // Checked earlier.
+ assert username != null;
+ subject.getPrincipals().add(new TOTPPrincipal(username));
// Bypass c14n. We already operate on a canonical name, so just re-confirm it.
profileRequestContext.ensureSubcontext(SubjectCanonicalizationContext.class).setPrincipalName(
diff --git a/totp-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/authn/TOTP/TOTP-authenticator.xml b/totp-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/authn/TOTP/TOTP-authenticator.xml
index e8ee79c..b3cbe1a 100644
--- a/totp-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/authn/TOTP/TOTP-authenticator.xml
+++ b/totp-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/authn/TOTP/TOTP-authenticator.xml
@@ -12,9 +12,6 @@
default-init-method="initialize"
default-destroy-method="destroy">
- <bean class="net.shibboleth.ext.spring.config.IdentifiableBeanPostProcessor" />
- <bean class="net.shibboleth.idp.profile.impl.ProfileActionBeanPostProcessor" />
-
<bean id="DefaultAuthenticator" class="net.shibboleth.idp.plugin.authn.totp.impl.GoogleTOTPAuthenticator" lazy-init="true" />
</beans>
diff --git a/totp-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/authn/TOTP/TOTP-beans.xml b/totp-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/authn/TOTP/TOTP-beans.xml
index 548082b..640ff7c 100644
--- a/totp-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/authn/TOTP/TOTP-beans.xml
+++ b/totp-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/authn/TOTP/TOTP-beans.xml
@@ -19,21 +19,19 @@
p:basenames="classpath:/net/shibboleth/idp/plugin/authn/totp/messages"
p:defaultEncoding="UTF-8" />
- <bean id="InternalHttpServletRequest" class="net.shibboleth.utilities.java.support.net.ThreadLocalHttpServletRequestProxy" />
-
<!-- Default username comes from previous c14n or session. -->
<bean id="DefaultUsernameLookupStrategy"
class="net.shibboleth.idp.session.context.navigate.CanonicalUsernameLookupStrategy" />
<bean id="ExtractTOTPFromHeader"
class="net.shibboleth.idp.plugin.authn.totp.impl.ExtractTOTPFromHeader" scope="prototype"
- p:httpServletRequest-ref="InternalHttpServletRequest"
+ p:httpServletRequestSupplier-ref="shibboleth.HttpServletRequestSupplier"
p:usernameLookupStrategy="#{getObject('shibboleth.authn.TOTP.UsernameLookupStrategy') ?: getObject('DefaultUsernameLookupStrategy')}"
p:headerName="#{'%{idp.authn.TOTP.headerName:X-Shibboleth-TOTP}'.trim()}" />
<bean id="ExtractTOTPFromFormRequest"
class="net.shibboleth.idp.plugin.authn.totp.impl.ExtractTOTPFromFormRequest" scope="prototype"
- p:httpServletRequest-ref="InternalHttpServletRequest"
+ p:httpServletRequestSupplier-ref="shibboleth.HttpServletRequestSupplier"
p:usernameLookupStrategy="#{getObject('shibboleth.authn.TOTP.UsernameLookupStrategy') ?: getObject('DefaultUsernameLookupStrategy')}"
p:fieldName="#{'%{idp.authn.TOTP.fieldName:tokencode}'.trim()}" />
@@ -42,17 +40,9 @@
p:validators="#{getObject('shibboleth.authn.TOTP.Validator') ?: getObject('DefaultTOTPValidator')}"
p:resultCachingPredicate="#{getObject('shibboleth.authn.TOTP.resultCachingPredicate')}"
p:addDefaultPrincipals="%{idp.authn.TOTP.addDefaultPrincipals:true}"
- p:classifiedMessages="#{getObject('shibboleth.authn.TOTP.ClassifiedMessageMap') ?: getObject('DefaultTOTPClassifiedMessageMap')}"
+ p:classifiedMessages="#{getObject('shibboleth.authn.TOTP.ClassifiedMessageMap')}"
p:lockoutManager="#{getObject('shibboleth.authn.TOTP.AccountLockoutManager')}" />
- <util:map id="DefaultTOTPClassifiedMessageMap">
- <entry key="InvalidCredentials">
- <list>
- <value>InvalidCredentials</value>
- </list>
- </entry>
- </util:map>
-
<!-- These are singletons acting as default "back-ends". -->
<bean id="DefaultTOTPValidator" class="net.shibboleth.idp.plugin.authn.totp.impl.TOTPCredentialValidator" lazy-init="true"
@@ -63,4 +53,28 @@
p:attributeResolver-ref="shibboleth.AttributeResolverService"
p:sourceAttribute="#{'%{idp.authn.TOTP.tokenSeedAttribute:tokenSeeds}'.trim()}" />
+ <!-- Used in views to calculate CSP hashes and nonces, remove and adjust beans in flow when compatibility bumped past 5.0 -->
+
+ <bean id="TOTPCSPDigester" class="net.shibboleth.shared.codec.StringDigester"
+ c:algorithm="SHA256" c:format="BASE64" />
+
+ <bean id="TOTPCSPNonce" destroy-method=""
+ class="net.shibboleth.shared.security.IdentifierGenerationStrategy" factory-method="getInstance">
+ <constructor-arg>
+ <util:constant
+ static-field="net.shibboleth.shared.security.IdentifierGenerationStrategy.ProviderType.SECURE" />
+ </constructor-arg>
+ <constructor-arg>
+ <bean class="net.shibboleth.shared.security.RandomIdentifierParameterSpec"
+ c:identifierSize="16">
+ <constructor-arg name="source">
+ <null/>
+ </constructor-arg>
+ <constructor-arg name="identifierEncoder">
+ <null/>
+ </constructor-arg>
+ </bean>
+ </constructor-arg>
+ </bean>
+
</beans>
diff --git a/totp-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/authn/TOTP/TOTP-flow.xml b/totp-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/authn/TOTP/TOTP-flow.xml
index f912c4c..18c4884 100644
--- a/totp-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/authn/TOTP/TOTP-flow.xml
+++ b/totp-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/authn/TOTP/TOTP-flow.xml
@@ -27,7 +27,9 @@
<evaluate expression="authenticationContext.getSubcontext(T(net.shibboleth.idp.ui.context.RelyingPartyUIContext))" result="viewScope.rpUIContext" />
<evaluate expression="authenticationContext.getSubcontext(T(net.shibboleth.idp.authn.context.AuthenticationErrorContext))" result="viewScope.authenticationErrorContext" />
<evaluate expression="authenticationContext.getSubcontext(T(net.shibboleth.idp.authn.context.AuthenticationWarningContext))" result="viewScope.authenticationWarningContext" />
- <evaluate expression="T(net.shibboleth.utilities.java.support.codec.HTMLEncoder)" result="viewScope.encoder" />
+ <evaluate expression="flowRequestContext.getActiveFlow().getApplicationContext().getBean('TOTPCSPDigester')" result="viewScope.cspDigester" />
+ <evaluate expression="flowRequestContext.getActiveFlow().getApplicationContext().getBean('TOTPCSPNonce')" result="viewScope.cspNonce" />
+ <evaluate expression="T(net.shibboleth.shared.codec.HTMLEncoder)" result="viewScope.encoder" />
<evaluate expression="flowRequestContext.getExternalContext().getNativeRequest()" result="viewScope.request" />
<evaluate expression="flowRequestContext.getExternalContext().getNativeResponse()" result="viewScope.response" />
<evaluate
diff --git a/totp-impl/src/main/resources/net/shibboleth/idp/plugin/authn/totp/views/totp.vm b/totp-impl/src/main/resources/net/shibboleth/idp/plugin/authn/totp/views/totp.vm
index 68bbab9..ec1a68e 100644
--- a/totp-impl/src/main/resources/net/shibboleth/idp/plugin/authn/totp/views/totp.vm
+++ b/totp-impl/src/main/resources/net/shibboleth/idp/plugin/authn/totp/views/totp.vm
@@ -11,6 +11,8 @@
## authenticationWarningContext - context with login warning state
## rpUIContext - the context with SP UI information from the metadata
## encoder - HTMLEncoder class
+## cspDigester - Calculates base64-encoded SHA-2 hashes (call apply)
+## cspNonce - Calculates secure nonces (call generateIdentifier)
## request - HttpServletRequest
## response - HttpServletResponse
## environment - Spring Environment object for property resolution
@@ -18,6 +20,8 @@
##
#set ($rpContext = $profileRequestContext.getSubcontext('net.shibboleth.idp.profile.context.RelyingPartyContext'))
##
+#set ($onClick = "this.childNodes[0].nodeValue='#springMessageText('idp.login.pleasewait', 'Logging in, please wait...')'")
+$response.addHeader("Content-Security-Policy", "script-src-attr 'unsafe-hashes' 'sha256-$cspDigester.apply($onClick)'")
<!DOCTYPE html>
<html>
<head>
@@ -70,8 +74,7 @@
<div class="grid">
<div class="grid-item">
<button type="submit" name="_eventId_proceed"
- onClick="this.childNodes[0].nodeValue='#springMessageText("idp.login.pleasewait", "Logging in, please wait...")'"
- >#springMessageText("idp.login.login", "Login")</button>
+ onClick="$onClick">#springMessageText("idp.login.login", "Login")</button>
</div>
</div>
</form>
diff --git a/totp-impl/src/test/java/net/shibboleth/idp/plugin/authn/totp/impl/AttributeResolverSeedSourceTest.java b/totp-impl/src/test/java/net/shibboleth/idp/plugin/authn/totp/impl/AttributeResolverSeedSourceTest.java
index 305bbc4..f25bfd2 100644
--- a/totp-impl/src/test/java/net/shibboleth/idp/plugin/authn/totp/impl/AttributeResolverSeedSourceTest.java
+++ b/totp-impl/src/test/java/net/shibboleth/idp/plugin/authn/totp/impl/AttributeResolverSeedSourceTest.java
@@ -17,7 +17,6 @@ package net.shibboleth.idp.plugin.authn.totp.impl;
import static org.testng.Assert.*;
import java.util.Collection;
-import java.util.Collections;
import java.util.Iterator;
import java.util.List;
@@ -38,6 +37,7 @@ import net.shibboleth.idp.plugin.authn.totp.context.TOTPContext;
import net.shibboleth.idp.profile.testing.RequestContextBuilder;
import net.shibboleth.shared.codec.Base32Support;
import net.shibboleth.shared.codec.EncodingException;
+import net.shibboleth.shared.collection.CollectionSupport;
import net.shibboleth.shared.component.ComponentInitializationException;
import net.shibboleth.shared.testing.MockReloadableService;
@@ -54,7 +54,7 @@ public class AttributeResolverSeedSourceTest {
final String two = Base32Support.encode("two".getBytes(), false);
final IdPAttribute single = new IdPAttribute("single");
- single.setValues(Collections.singletonList(StringAttributeValue.valueOf(one)));
+ single.setValues(CollectionSupport.singletonList(StringAttributeValue.valueOf(one)));
final AttributeDefinition singledef = new MockAttributeDefinition("single", single);
singledef.initialize();
@@ -142,8 +142,8 @@ public class AttributeResolverSeedSourceTest {
final AttributeResolverImpl result = new AttributeResolverImpl();
result.setId("test");
- result.setAttributeDefinitions(definitions == null ? Collections.emptyList() : definitions);
- result.setDataConnectors(connectors == null ? Collections.emptyList() : connectors);
+ result.setAttributeDefinitions(definitions == null ? CollectionSupport.emptyList() : definitions);
+ result.setDataConnectors(connectors == null ? CollectionSupport.emptyList() : connectors);
result.initialize();
return result;
diff --git a/totp-impl/src/test/java/net/shibboleth/idp/plugin/authn/totp/impl/ExtractTOTPFromFormRequestTest.java b/totp-impl/src/test/java/net/shibboleth/idp/plugin/authn/totp/impl/ExtractTOTPFromFormRequestTest.java
index 6c5f262..abba6f8 100644
--- a/totp-impl/src/test/java/net/shibboleth/idp/plugin/authn/totp/impl/ExtractTOTPFromFormRequestTest.java
+++ b/totp-impl/src/test/java/net/shibboleth/idp/plugin/authn/totp/impl/ExtractTOTPFromFormRequestTest.java
@@ -70,27 +70,33 @@ public class ExtractTOTPFromFormRequestTest extends BaseAuthenticationContextTes
}
@Test public void testWrongField() throws Exception {
- ((MockHttpServletRequest) action.getHttpServletRequest()).addParameter("Bar", "123456");
+ if (action.getHttpServletRequest() instanceof MockHttpServletRequest mock) {
+ mock.addParameter("Bar", "123456");
+ }
final Event event = action.execute(src);
ActionTestingSupport.assertEvent(event, AuthnEventIds.NO_CREDENTIALS);
}
@Test public void testInvalidFormat() throws Exception {
- ((MockHttpServletRequest) action.getHttpServletRequest()).addParameter("Foo", "A123456");
+ if (action.getHttpServletRequest() instanceof MockHttpServletRequest mock) {
+ mock.addParameter("Foo", "A123456");
+ }
final Event event = action.execute(src);
ActionTestingSupport.assertEvent(event, AuthnEventIds.INVALID_CREDENTIALS);
}
@Test public void testValid() throws Exception {
- ((MockHttpServletRequest) action.getHttpServletRequest()).addParameter("Foo", "123456");
+ if (action.getHttpServletRequest() instanceof MockHttpServletRequest mock) {
+ mock.addParameter("Foo", "123456");
+ }
final Event event = action.execute(src);
ActionTestingSupport.assertProceedEvent(event);
- final AuthenticationContext authCtx = prc.getSubcontext(AuthenticationContext.class);
+ final AuthenticationContext authCtx = prc.ensureSubcontext(AuthenticationContext.class);
final TOTPContext totpCtx = authCtx.getSubcontext(TOTPContext.class);
- Assert.assertNotNull(totpCtx);
+ assert totpCtx != null;
Assert.assertEquals(totpCtx.getUsername(), "jdoe");
Assert.assertEquals(totpCtx.getTokenCode(), Integer.valueOf(123456));
}
diff --git a/totp-impl/src/test/java/net/shibboleth/idp/plugin/authn/totp/impl/ExtractTOTPFromHeaderTest.java b/totp-impl/src/test/java/net/shibboleth/idp/plugin/authn/totp/impl/ExtractTOTPFromHeaderTest.java
index 753220a..f483a6d 100644
--- a/totp-impl/src/test/java/net/shibboleth/idp/plugin/authn/totp/impl/ExtractTOTPFromHeaderTest.java
+++ b/totp-impl/src/test/java/net/shibboleth/idp/plugin/authn/totp/impl/ExtractTOTPFromHeaderTest.java
@@ -70,27 +70,33 @@ public class ExtractTOTPFromHeaderTest extends BaseAuthenticationContextTest {
}
@Test public void testWrongHeader() {
- ((MockHttpServletRequest) action.getHttpServletRequest()).addHeader("Foo", "123456");
+ if (action.getHttpServletRequest() instanceof MockHttpServletRequest mock) {
+ mock.addHeader("Foo", "123456");
+ }
final Event event = action.execute(src);
ActionTestingSupport.assertEvent(event, AuthnEventIds.NO_CREDENTIALS);
}
@Test public void testInvalidFormat() {
- ((MockHttpServletRequest) action.getHttpServletRequest()).addHeader("X-Foo", "A123456");
+ if (action.getHttpServletRequest() instanceof MockHttpServletRequest mock) {
+ mock.addHeader("X-Foo", "A123456");
+ }
final Event event = action.execute(src);
ActionTestingSupport.assertEvent(event, AuthnEventIds.INVALID_CREDENTIALS);
}
@Test public void testValid() {
- ((MockHttpServletRequest) action.getHttpServletRequest()).addHeader("X-Foo", "123456");
+ if (action.getHttpServletRequest() instanceof MockHttpServletRequest mock) {
+ mock.addHeader("X-Foo", "123456");
+ }
final Event event = action.execute(src);
ActionTestingSupport.assertProceedEvent(event);
- final AuthenticationContext authCtx = prc.getSubcontext(AuthenticationContext.class);
+ final AuthenticationContext authCtx = prc.ensureSubcontext(AuthenticationContext.class);
final TOTPContext totpCtx = authCtx.getSubcontext(TOTPContext.class);
- Assert.assertNotNull(totpCtx);
+ assert totpCtx != null;
Assert.assertEquals(totpCtx.getUsername(), "jdoe");
Assert.assertEquals(totpCtx.getTokenCode(), Integer.valueOf(123456));
}
diff --git a/totp-impl/src/test/java/net/shibboleth/idp/plugin/authn/totp/impl/GoogleTOTPAuthenticatorTest.java b/totp-impl/src/test/java/net/shibboleth/idp/plugin/authn/totp/impl/GoogleTOTPAuthenticatorTest.java
index 18993f9..ed4ec8f 100644
--- a/totp-impl/src/test/java/net/shibboleth/idp/plugin/authn/totp/impl/GoogleTOTPAuthenticatorTest.java
+++ b/totp-impl/src/test/java/net/shibboleth/idp/plugin/authn/totp/impl/GoogleTOTPAuthenticatorTest.java
@@ -22,6 +22,7 @@ import java.util.regex.Pattern;
import javax.security.auth.login.LoginException;
+import net.shibboleth.idp.authn.AuthenticationResult;
import net.shibboleth.idp.authn.AuthnEventIds;
import net.shibboleth.idp.authn.context.AuthenticationContext;
import net.shibboleth.idp.authn.context.AuthenticationErrorContext;
@@ -76,7 +77,7 @@ public class GoogleTOTPAuthenticatorTest extends BaseAuthenticationContextTest {
}
@Test public void testMissingContext() throws ComponentInitializationException {
- prc.getSubcontext(AuthenticationContext.class).setAttemptedFlow(authenticationFlows.get(0));
+ prc.ensureSubcontext(AuthenticationContext.class).setAttemptedFlow(authenticationFlows.get(0));
validator.initialize();
action.initialize();
@@ -86,7 +87,7 @@ public class GoogleTOTPAuthenticatorTest extends BaseAuthenticationContextTest {
}
@Test public void testMissingUser() throws ComponentInitializationException {
- final AuthenticationContext ac = prc.getSubcontext(AuthenticationContext.class);
+ final AuthenticationContext ac = prc.ensureSubcontext(AuthenticationContext.class);
ac.setAttemptedFlow(authenticationFlows.get(0));
ac.ensureSubcontext(TOTPContext.class);
@@ -99,7 +100,7 @@ public class GoogleTOTPAuthenticatorTest extends BaseAuthenticationContextTest {
@Test public void testMissingCode() throws ComponentInitializationException {
- final AuthenticationContext ac = prc.getSubcontext(AuthenticationContext.class);
+ final AuthenticationContext ac = prc.ensureSubcontext(AuthenticationContext.class);
ac.setAttemptedFlow(authenticationFlows.get(0));
ac.ensureSubcontext(TOTPContext.class).setUsername("foo").getTokenSeeds().add("foo".getBytes());
@@ -111,7 +112,7 @@ public class GoogleTOTPAuthenticatorTest extends BaseAuthenticationContextTest {
}
@Test public void testMissingSeeds() throws ComponentInitializationException {
- final AuthenticationContext ac = prc.getSubcontext(AuthenticationContext.class);
+ final AuthenticationContext ac = prc.ensureSubcontext(AuthenticationContext.class);
ac.setAttemptedFlow(authenticationFlows.get(0));
ac.ensureSubcontext(TOTPContext.class).setUsername("foo").setTokenCode(123456);
@@ -123,7 +124,7 @@ public class GoogleTOTPAuthenticatorTest extends BaseAuthenticationContextTest {
}
@Test public void testUnmatchedUser() throws Exception {
- final AuthenticationContext ac = prc.getSubcontext(AuthenticationContext.class);
+ final AuthenticationContext ac = prc.ensureSubcontext(AuthenticationContext.class);
ac.setAttemptedFlow(authenticationFlows.get(0));
ac.ensureSubcontext(TOTPContext.class).setUsername("bar").setTokenCode(123456).getTokenSeeds().add("foo".getBytes());
@@ -138,7 +139,7 @@ public class GoogleTOTPAuthenticatorTest extends BaseAuthenticationContextTest {
}
@Test public void testInvalidSeed() throws ComponentInitializationException {
- final AuthenticationContext ac = prc.getSubcontext(AuthenticationContext.class);
+ final AuthenticationContext ac = prc.ensureSubcontext(AuthenticationContext.class);
ac.setAttemptedFlow(authenticationFlows.get(0));
ac.ensureSubcontext(TOTPContext.class).setUsername("foo").setTokenCode(123456).getTokenSeeds().add("foo".getBytes());
@@ -147,12 +148,13 @@ public class GoogleTOTPAuthenticatorTest extends BaseAuthenticationContextTest {
final Event event = action.execute(src);
ActionTestingSupport.assertEvent(event, AuthnEventIds.INVALID_CREDENTIALS);
- AuthenticationErrorContext errorCtx = ac.getSubcontext(AuthenticationErrorContext.class);
+ final AuthenticationErrorContext errorCtx = ac.getSubcontext(AuthenticationErrorContext.class);
+ assert errorCtx != null;
Assert.assertTrue(errorCtx.getExceptions().get(0) instanceof LoginException);
}
@Test public void testInvalidCode() throws ComponentInitializationException, DecodingException {
- final AuthenticationContext ac = prc.getSubcontext(AuthenticationContext.class);
+ final AuthenticationContext ac = prc.ensureSubcontext(AuthenticationContext.class);
ac.setAttemptedFlow(authenticationFlows.get(0));
ac.ensureSubcontext(TOTPContext.class).setUsername("foo").setTokenCode(123456).getTokenSeeds().add(
Base32Support.decode("G24YUKCHHXRDWCPR"));
@@ -162,12 +164,13 @@ public class GoogleTOTPAuthenticatorTest extends BaseAuthenticationContextTest {
final Event event = action.execute(src);
ActionTestingSupport.assertEvent(event, AuthnEventIds.INVALID_CREDENTIALS);
- AuthenticationErrorContext errorCtx = ac.getSubcontext(AuthenticationErrorContext.class);
+ final AuthenticationErrorContext errorCtx = ac.getSubcontext(AuthenticationErrorContext.class);
+ assert errorCtx != null;
Assert.assertTrue(errorCtx.getExceptions().get(0) instanceof LoginException);
}
@Test public void testSuccess() throws ComponentInitializationException, DecodingException {
- final AuthenticationContext ac = prc.getSubcontext(AuthenticationContext.class);
+ final AuthenticationContext ac = prc.ensureSubcontext(AuthenticationContext.class);
ac.setAttemptedFlow(authenticationFlows.get(0));
final GoogleAuthenticator auth = new GoogleAuthenticator();
@@ -184,8 +187,9 @@ public class GoogleTOTPAuthenticatorTest extends BaseAuthenticationContextTest {
final Event event = action.execute(src);
ActionTestingSupport.assertProceedEvent(event);
- Assert.assertNotNull(ac.getAuthenticationResult());
- Assert.assertEquals(ac.getAuthenticationResult().getSubject().getPrincipals(TOTPPrincipal.class).iterator()
+ final AuthenticationResult result = ac.getAuthenticationResult();
+ assert result != null;
+ Assert.assertEquals(result.getSubject().getPrincipals(TOTPPrincipal.class).iterator()
.next().getName(), "foo");
}
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
More information about the commits
mailing list