[java-idp-plugin-webauthn] branch main updated: Fix user handle creation so it honours any existing userhandle stored
Phil Smart
philip.smart at jisc.ac.uk
Fri Feb 16 14:21:51 UTC 2024
This is an automated email from the git hooks/post-receive script.
philsmart pushed a commit to branch main
in repository java-idp-plugin-webauthn.
View the commit online:
http://git.shibboleth.net/view/?p=java-idp-plugin-webauthn.git;a=commit;h=0bde56b7e27bbc527a644c663621bfe2a77fcafd
The following commit(s) were added to refs/heads/main by this push:
new 0bde56b Fix user handle creation so it honours any existing userhandle stored
0bde56b is described below
commit 0bde56b7e27bbc527a644c663621bfe2a77fcafd
Author: Phil Smart <philip.smart at jisc.ac.uk>
AuthorDate: Fri Feb 16 14:21:49 2024 +0000
Fix user handle creation so it honours any existing userhandle stored
---
.../impl/AbstractWebAuthnRegistrationAction.java | 4 +-
.../webauthn/admin/impl/GenerateUserHandle.java | 55 ++++++++++++++++++----
2 files changed, 47 insertions(+), 12 deletions(-)
diff --git a/webauthn-impl/src/main/java/net/shibboleth/idp/plugin/authn/webauthn/admin/impl/AbstractWebAuthnRegistrationAction.java b/webauthn-impl/src/main/java/net/shibboleth/idp/plugin/authn/webauthn/admin/impl/AbstractWebAuthnRegistrationAction.java
index f24441c..946b65e 100644
--- a/webauthn-impl/src/main/java/net/shibboleth/idp/plugin/authn/webauthn/admin/impl/AbstractWebAuthnRegistrationAction.java
+++ b/webauthn-impl/src/main/java/net/shibboleth/idp/plugin/authn/webauthn/admin/impl/AbstractWebAuthnRegistrationAction.java
@@ -67,7 +67,6 @@ public abstract class AbstractWebAuthnRegistrationAction extends AbstractProfile
@NonnullBeforeExec private WebAuthnAuthenticationClient webAuthnClient;
/** The credential respository to store valid credentials in.*/
- // TODO replace with an adaptor to the storage service?
@NonnullAfterInit private StorageServiceCredentialRepository credentialRepository;
@@ -128,8 +127,7 @@ public abstract class AbstractWebAuthnRegistrationAction extends AbstractProfile
*
* @return the credential repository.
*/
- //TODO should even storage operations go through the client.
- public StorageServiceCredentialRepository getCredentialRepository() {
+ @NonnullAfterInit public StorageServiceCredentialRepository getCredentialRepository() {
return credentialRepository;
}
diff --git a/webauthn-impl/src/main/java/net/shibboleth/idp/plugin/authn/webauthn/admin/impl/GenerateUserHandle.java b/webauthn-impl/src/main/java/net/shibboleth/idp/plugin/authn/webauthn/admin/impl/GenerateUserHandle.java
index 8df48a5..4c3bb4e 100644
--- a/webauthn-impl/src/main/java/net/shibboleth/idp/plugin/authn/webauthn/admin/impl/GenerateUserHandle.java
+++ b/webauthn-impl/src/main/java/net/shibboleth/idp/plugin/authn/webauthn/admin/impl/GenerateUserHandle.java
@@ -19,6 +19,7 @@ package net.shibboleth.idp.plugin.authn.webauthn.admin.impl;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
+import java.util.Optional;
import java.util.function.Function;
import javax.annotation.Nonnull;
@@ -29,15 +30,21 @@ import org.opensaml.profile.action.EventIds;
import org.opensaml.profile.context.ProfileRequestContext;
import org.slf4j.Logger;
+import com.yubico.webauthn.data.ByteArray;
+
+import net.shibboleth.idp.authn.AuthnEventIds;
import net.shibboleth.idp.plugin.authn.webauthn.context.WebAuthnRegistrationContext;
+import net.shibboleth.shared.annotation.constraint.NonnullBeforeExec;
import net.shibboleth.shared.logic.Constraint;
import net.shibboleth.shared.primitive.LoggerFactory;
/**
- * An action to generate a UserHandle as the user.id. This is used by the IdP to map a public key credential to a
- * users session map of public keys, and by the Authenticator to map the IdP's ID (RelyingParty ID) and the
+ * An action to generate or lookup a UserHandle as the user.id. This is used by the IdP to map a public key credential
+ * to a users session map of public keys, and by the Authenticator to map the IdP's ID (RelyingParty ID) and the
* User Handle to a public key credential source (which contains the private key).
*
+ * <p>The same user should use the same UserHandle.</p>
+ *
* @event {@link org.opensaml.profile.action.EventIds#PROCEED_EVENT_ID}
* @event {@link org.opensaml.profile.action.EventIds#INVALID_PROFILE_CTX}
* @post a UserHandle is added to the registration context
@@ -50,6 +57,9 @@ public class GenerateUserHandle extends AbstractWebAuthnRegistrationAction {
/** Strategy used to generate the UserHandle. */
@Nonnull private Function<ProfileRequestContext,byte[]> userHandleGeneratorStrategy;
+ /** The stashed username.*/
+ @NonnullBeforeExec private String username;
+
/** Constructor. */
public GenerateUserHandle() {
userHandleGeneratorStrategy = new DefaultUserHandleGenerator();
@@ -66,19 +76,46 @@ public class GenerateUserHandle extends AbstractWebAuthnRegistrationAction {
userHandleGeneratorStrategy =
Constraint.isNotNull(strategy, "Challenge Generator cannot be null");
}
+
+ /** {@inheritDoc} */
+ @Override
+ protected boolean doPreExecute(@Nonnull final ProfileRequestContext profileRequestContext,
+ @Nonnull final WebAuthnRegistrationContext context) {
+
+ if (!super.doPreExecute(profileRequestContext, context)) {
+ return false;
+ }
+
+ username = context.getUsername();
+ if (username == null) {
+ log.error("{} Username not available in registration context", getLogPrefix());
+ ActionSupport.buildEvent(profileRequestContext, AuthnEventIds.NO_CREDENTIALS);
+ return false;
+ }
+
+ return true;
+ }
/** {@inheritDoc} */
@Override protected void doExecute(@Nonnull final ProfileRequestContext profileRequestContext,
@Nonnull final WebAuthnRegistrationContext context) {
- final byte[] userHandle = userHandleGeneratorStrategy.apply(profileRequestContext);
- if (userHandle == null) {
- log.trace("{} Generated UserHandle was null", getLogPrefix());
- ActionSupport.buildEvent(profileRequestContext, EventIds.INVALID_PROFILE_CTX);
- return;
+ final Optional<ByteArray> existingUserHandle = getCredentialRepository().getUserHandleForUsername(username);
+
+ if (existingUserHandle.isPresent()) {
+ final byte[] handleAsBytes = existingUserHandle.get().getBytes();
+ assert handleAsBytes != null;
+ context.setUserHandle(handleAsBytes);
+ } else {
+ final byte[] userHandle = userHandleGeneratorStrategy.apply(profileRequestContext);
+ if (userHandle == null) {
+ log.trace("{} Generated UserHandle was null", getLogPrefix());
+ ActionSupport.buildEvent(profileRequestContext, EventIds.INVALID_PROFILE_CTX);
+ return;
+ }
+ log.trace("{} Generated UserHandle '{}'",getLogPrefix(),userHandle);
+ context.setUserHandle(userHandle);
}
- log.trace("{} Generated UserHandle '{}'",getLogPrefix(),userHandle);
- context.setUserHandle(userHandle);
}
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
More information about the commits
mailing list