[java-idp-plugin-totp] branch main updated: Add URL and QR code generation to CLI.
Scott Cantor
cantor.2 at osu.edu
Thu Aug 13 00:27:30 UTC 2020
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=2251f26d6c99fea2a5bd95cf79d4af81b5ac7933
The following commit(s) were added to refs/heads/main by this push:
new 2251f26 Add URL and QR code generation to CLI.
2251f26 is described below
commit 2251f26d6c99fea2a5bd95cf79d4af81b5ac7933
Author: Scott Cantor <cantor.2 at osu.edu>
AuthorDate: Wed Aug 12 20:27:20 2020 -0400
Add URL and QR code generation to CLI.
---
.../plugin/totp/impl/GoogleTOTPAuthenticator.java | 38 ++++++++++++++++++++--
.../idp/plugin/totp/impl/TOTPAuthenticator.java | 14 +++++++-
.../totp/impl/TOTPAuthenticatorArguments.java | 31 ++++++++++++++++++
.../idp/plugin/totp/impl/TOTPAuthenticatorCLI.java | 7 +++-
4 files changed, 86 insertions(+), 4 deletions(-)
diff --git a/totp-impl/src/main/java/net/shibboleth/idp/plugin/totp/impl/GoogleTOTPAuthenticator.java b/totp-impl/src/main/java/net/shibboleth/idp/plugin/totp/impl/GoogleTOTPAuthenticator.java
index 3972b5d..9558174 100644
--- a/totp-impl/src/main/java/net/shibboleth/idp/plugin/totp/impl/GoogleTOTPAuthenticator.java
+++ b/totp-impl/src/main/java/net/shibboleth/idp/plugin/totp/impl/GoogleTOTPAuthenticator.java
@@ -21,6 +21,7 @@ import java.security.GeneralSecurityException;
import java.util.Collection;
import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
import net.shibboleth.utilities.java.support.annotation.constraint.NonnullAfterInit;
import net.shibboleth.utilities.java.support.annotation.constraint.NotEmpty;
@@ -33,10 +34,12 @@ import net.shibboleth.utilities.java.support.component.AbstractInitializableComp
import net.shibboleth.utilities.java.support.component.ComponentInitializationException;
import net.shibboleth.utilities.java.support.component.ComponentSupport;
import net.shibboleth.utilities.java.support.logic.Constraint;
+import net.shibboleth.utilities.java.support.primitive.StringSupport;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import com.google.common.net.UrlEscapers;
import com.warrenstrange.googleauth.GoogleAuthenticator;
import com.warrenstrange.googleauth.GoogleAuthenticatorConfig;
import com.warrenstrange.googleauth.GoogleAuthenticatorKey;
@@ -79,19 +82,26 @@ public class GoogleTOTPAuthenticator extends AbstractInitializableComponent impl
}
/** {@inheritDoc} */
- public TOTPCredential createCredential() throws GeneralSecurityException {
+ public TOTPCredential createCredential(@Nullable @NotEmpty final String issuer,
+ @Nullable @NotEmpty final String accountName) throws GeneralSecurityException {
final byte[] secret;
+ final String encodedSecret;
final GoogleAuthenticatorKey cred = authenticator.createCredentials();
+ final String trimmedIssuer = StringSupport.trimOrNull(issuer);
+ final String trimmedName = StringSupport.trimOrNull(accountName);
+
try {
switch (authconfig.getKeyRepresentation()) {
case BASE32:
secret = Base32Support.decode(cred.getKey());
+ encodedSecret = cred.getKey();
break;
case BASE64:
secret = Base64Support.decode(cred.getKey());
+ encodedSecret = Base32Support.encode(secret, false);
break;
default:
@@ -102,12 +112,36 @@ public class GoogleTOTPAuthenticator extends AbstractInitializableComponent impl
public byte[] getKey() {
return secret;
}
+
+ public String getTOTPURL() {
+ final String label;
+ if (trimmedName != null) {
+ if (trimmedIssuer != null) {
+ label = trimmedIssuer + ":" + trimmedName;
+ } else {
+ label = trimmedName;
+ }
+
+ } else {
+ label = null;
+ }
+
+ final StringBuilder url = new StringBuilder();
+ url.append("otpauth://totp/")
+ .append(UrlEscapers.urlPathSegmentEscaper().escape(label))
+ .append("?secret=")
+ .append(UrlEscapers.urlFormParameterEscaper().escape(encodedSecret));
+ if (trimmedIssuer != null) {
+ url.append("&issuer=").append(UrlEscapers.urlFormParameterEscaper().escape(issuer));
+ }
+ return url.toString();
+ }
public Collection<Integer> getScratchCodes() {
return cred.getScratchCodes();
}
};
- } catch (final DecodingException e) {
+ } catch (final EncodingException|DecodingException e) {
throw new GeneralSecurityException(e);
}
}
diff --git a/totp-impl/src/main/java/net/shibboleth/idp/plugin/totp/impl/TOTPAuthenticator.java b/totp-impl/src/main/java/net/shibboleth/idp/plugin/totp/impl/TOTPAuthenticator.java
index cde579a..2668145 100644
--- a/totp-impl/src/main/java/net/shibboleth/idp/plugin/totp/impl/TOTPAuthenticator.java
+++ b/totp-impl/src/main/java/net/shibboleth/idp/plugin/totp/impl/TOTPAuthenticator.java
@@ -21,6 +21,7 @@ import java.security.GeneralSecurityException;
import java.util.Collection;
import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
import net.shibboleth.utilities.java.support.annotation.constraint.NonnullElements;
import net.shibboleth.utilities.java.support.annotation.constraint.NotEmpty;
@@ -35,11 +36,15 @@ public interface TOTPAuthenticator {
/**
* Generate a new credential.
*
+ * @param issuer TOTP credential issuer
+ * @param accountName TOTP account holder
+ *
* @return a new credential
*
* @throws GeneralSecurityException if unable to generate the credential
*/
- @Nonnull TOTPCredential createCredential() throws GeneralSecurityException;
+ @Nonnull TOTPCredential createCredential(@Nullable @NotEmpty final String issuer,
+ @Nullable @NotEmpty final String accountName) throws GeneralSecurityException;
/**
* Validate a secret and code.
@@ -61,6 +66,13 @@ public interface TOTPAuthenticator {
*/
@Nonnull @NotEmpty byte[] getKey();
+ /**
+ * Get the TOTP URL associated with the credential.
+ *
+ * @return TOTP URL
+ */
+ @Nonnull @NotEmpty String getTOTPURL();
+
/**
* Get the list of scratch codes.
*
diff --git a/totp-impl/src/main/java/net/shibboleth/idp/plugin/totp/impl/TOTPAuthenticatorArguments.java b/totp-impl/src/main/java/net/shibboleth/idp/plugin/totp/impl/TOTPAuthenticatorArguments.java
index 2e04202..a8d19cf 100644
--- a/totp-impl/src/main/java/net/shibboleth/idp/plugin/totp/impl/TOTPAuthenticatorArguments.java
+++ b/totp-impl/src/main/java/net/shibboleth/idp/plugin/totp/impl/TOTPAuthenticatorArguments.java
@@ -27,6 +27,7 @@ import net.shibboleth.ext.spring.cli.AbstractCommandLineArguments;
import net.shibboleth.utilities.java.support.annotation.constraint.NotEmpty;
import net.shibboleth.utilities.java.support.codec.Base32Support;
import net.shibboleth.utilities.java.support.codec.DecodingException;
+import net.shibboleth.utilities.java.support.primitive.StringSupport;
/**
* Arguments for {@link TOTPAuthenticatorCLI}.
@@ -39,6 +40,14 @@ public class TOTPAuthenticatorArguments extends AbstractCommandLineArguments {
@Parameter(names = "--authenticator")
@Nullable private String authenticatorName;
+ /** Credential issuer. */
+ @Parameter(names = "--issuer")
+ @Nullable private String issuer;
+
+ /** Credential account name. */
+ @Parameter(names = "--account")
+ @Nullable private String account;
+
/** Raw token seed when verifying codes. */
@Nullable private byte[] seed;
@@ -63,6 +72,24 @@ public class TOTPAuthenticatorArguments extends AbstractCommandLineArguments {
return seed;
}
+ /**
+ * Get the token issuer.
+ *
+ * @return token issuer
+ */
+ @Nullable @NotEmpty public String getIssuer() {
+ return StringSupport.trimOrNull(issuer);
+ }
+
+ /**
+ * Get the token account name.
+ *
+ * @return token account name
+ */
+ @Nullable @NotEmpty public String getAccountName() {
+ return StringSupport.trimOrNull(account);
+ }
+
/**
* Get token code to verify.
*
@@ -103,6 +130,10 @@ public class TOTPAuthenticatorArguments extends AbstractCommandLineArguments {
out.println();
out.println(String.format(" --%-20s %s", "authenticator",
"Specifies a non-default TOTPAuthenticator bean to use."));
+ out.println(String.format(" --%-20s %s", "issuer",
+ "Specifies a token issuer when generating a new credential."));
+ out.println(String.format(" --%-20s %s", "account",
+ "Specifies a token account name when generating a new credential."));
out.println();
}
diff --git a/totp-impl/src/main/java/net/shibboleth/idp/plugin/totp/impl/TOTPAuthenticatorCLI.java b/totp-impl/src/main/java/net/shibboleth/idp/plugin/totp/impl/TOTPAuthenticatorCLI.java
index 7178491..6e80e0d 100644
--- a/totp-impl/src/main/java/net/shibboleth/idp/plugin/totp/impl/TOTPAuthenticatorCLI.java
+++ b/totp-impl/src/main/java/net/shibboleth/idp/plugin/totp/impl/TOTPAuthenticatorCLI.java
@@ -23,6 +23,8 @@ import javax.annotation.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import com.google.common.net.UrlEscapers;
+
import net.shibboleth.ext.spring.cli.AbstractCommandLine;
import net.shibboleth.idp.Version;
import net.shibboleth.idp.plugin.totp.impl.TOTPAuthenticator.TOTPCredential;
@@ -86,8 +88,11 @@ public class TOTPAuthenticatorCLI extends AbstractCommandLine<TOTPAuthenticatorA
}
// Create a new token.
- final TOTPCredential tc = authenticator.createCredential();
+ final TOTPCredential tc = authenticator.createCredential(args.getIssuer(), args.getAccountName());
System.out.println("Seed: " + Base32Support.encode(tc.getKey(), false));
+ System.out.println("URL: " + tc.getTOTPURL());
+ System.out.println("QR Code: https://api.qrserver.com/v1/create-qr-code/?data=" +
+ UrlEscapers.urlFormParameterEscaper().escape(tc.getTOTPURL()) + "&size=200x200&ecc=M&margin=0");
} catch (final Exception e) {
if (args.isVerboseOutput()) {
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
More information about the commits
mailing list