[java-idp-plugin-totp] branch master updated: POM cleanup and starting on supporting classes.

Scott Cantor cantor.2 at osu.edu
Thu Jul 9 01:41:57 UTC 2020


This is an automated email from the git hooks/post-receive script.

scantor pushed a commit to branch master
in repository java-idp-plugin-totp.

View the commit online:
http://git.shibboleth.net/view/?p=java-idp-plugin-totp.git;a=commit;h=3c39176020578f2a803cd74d57c20759853d4555

The following commit(s) were added to refs/heads/master by this push:
       new  3c39176   POM cleanup and starting on supporting classes.
3c39176 is described below

commit 3c39176020578f2a803cd74d57c20759853d4555
Author: Scott Cantor <cantor.2 at osu.edu>
AuthorDate: Wed Jul 8 21:42:04 2020 -0400

    POM cleanup and starting on supporting classes.
---
 .project                                           |   6 +
 pom.xml                                            |  40 +----
 totp-dist/pom.xml                                  |   9 +-
 totp-dist/src/main/resources/bootstrap/id.property |   1 +
 totp-dist/src/main/resources/bootstrap/keys.txt    | 189 +++++++++++++++++++++
 .../src/main/resources/doc/GoogleAuth-LICENSE.txt  |  28 +++
 totp-impl/.checkstyle                              |  10 ++
 totp-impl/.project                                 |   6 +
 totp-impl/pom.xml                                  |  47 ++++-
 .../idp/plugin/totp/context/TOTPContext.java       | 171 +++++++++++++++++++
 .../idp/plugin/totp/context/package-info.java      |  20 +++
 .../idp/plugin/totp/impl/AbstractSeedSource.java   |  73 ++++++++
 .../totp/impl/AttributeResolverSeedSource.java     | 133 +++++++++++++++
 .../idp/plugin/totp/impl/StaticSeedSource.java     |  90 ++++++++++
 .../idp/plugin/totp/principal/TOTPPrincipal.java   |  89 ++++++++++
 .../idp/plugin/totp/principal/package-info.java    |  22 +++
 16 files changed, 894 insertions(+), 40 deletions(-)

diff --git a/.project b/.project
index 4e300c7..02906e1 100644
--- a/.project
+++ b/.project
@@ -10,8 +10,14 @@
 			<arguments>
 			</arguments>
 		</buildCommand>
+		<buildCommand>
+			<name>net.sf.eclipsecs.core.CheckstyleBuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
 	</buildSpec>
 	<natures>
 		<nature>org.eclipse.m2e.core.maven2Nature</nature>
+		<nature>net.sf.eclipsecs.core.CheckstyleNature</nature>
 	</natures>
 </projectDescription>
diff --git a/pom.xml b/pom.xml
index f203230..d1a3386 100644
--- a/pom.xml
+++ b/pom.xml
@@ -10,14 +10,15 @@
         <version>4.1.0-SNAPSHOT</version>
     </parent>
 
-    <name>java-idp-plugin-totp</name>
+    <name>Shibboleth IdP :: Plugins :: TOTP Login Flow</name>
+    <description>An IdP plugin providing TOTP login support.</description>
     <groupId>net.shibboleth.idp.plugin</groupId>
-    <artifactId>java-idp-plugin-totp</artifactId>
+    <artifactId>idp-plugin-totp</artifactId>
     <version>1.0.0-SNAPSHOT</version>
     <packaging>pom</packaging>
 
     <properties>
-        <automatic.module.name>net.shibboleth.idp.plugin.idp-authn-totp</automatic.module.name>
+        <plugin.base>totp</plugin.base>
         <idp.groupId>net.shibboleth.idp</idp.groupId>
         <idp.version>4.1.0-SNAPSHOT</idp.version>
         <checkstyle.configLocation>${project.basedir}/checkstyle.xml</checkstyle.configLocation>
@@ -41,38 +42,11 @@
     </repositories>
 
     <scm>
-        <connection>scm:git:https://git.shibboleth.net/git/${project.artifactId}</connection>
-        <developerConnection>scm:git:git at git.shibboleth.net:${project.artifactId}</developerConnection>
-        <url>https://git.shibboleth.net/view/?p=${project.artifactId}.git</url>
+        <connection>scm:git:https://git.shibboleth.net/git/java-${project.artifactId}</connection>
+        <developerConnection>scm:git:git at git.shibboleth.net:java-${project.artifactId}</developerConnection>
+        <url>https://git.shibboleth.net/view/?p=java-${project.artifactId}.git</url>
     </scm>
 
-    <dependencies>
-        <!-- provided dependencies -->
-        <dependency>
-            <groupId>net.shibboleth.utilities</groupId>
-            <artifactId>java-support</artifactId>
-            <version>8.1.0-SNAPSHOT</version>
-            <scope>provided</scope>
-        </dependency>
-        <dependency>
-            <groupId>net.shibboleth.ext</groupId>
-            <artifactId>spring-extensions</artifactId>
-            <scope>provided</scope>
-        </dependency>
-        <dependency>
-            <groupId>${spring-webflow.groupId}</groupId>
-            <artifactId>spring-webflow</artifactId>
-            <scope>provided</scope>
-        </dependency>
-        <dependency>
-            <groupId>${idp.groupId}</groupId>
-            <artifactId>idp-authn-api</artifactId>
-            <scope>provided</scope>
-        </dependency>
-
-        <!-- test dependencies -->
-    </dependencies>
-
     <dependencyManagement>
         <dependencies>
             <dependency>
diff --git a/totp-dist/pom.xml b/totp-dist/pom.xml
index 6056c2b..561bd7d 100644
--- a/totp-dist/pom.xml
+++ b/totp-dist/pom.xml
@@ -6,17 +6,18 @@
 
     <parent>
         <groupId>net.shibboleth.idp.plugin</groupId>
-        <artifactId>java-idp-plugin-totp</artifactId>
+        <artifactId>idp-plugin-totp</artifactId>
         <version>1.0.0-SNAPSHOT</version>
     </parent>
 
     <name>Shibboleth IdP :: Plugins :: TOTP Login Flow Distribution</name>
-    <artifactId>idp-plugin-totp-dist</artifactId>
+    <description>IdP TOTP plugin packaging.</description>
+    <artifactId>idp-plugin-${plugin.base}-dist</artifactId>
     <packaging>pom</packaging>
 
     <properties>
         <checkstyle.configLocation>${project.basedir}/../checkstyle.xml</checkstyle.configLocation>
-        <dist.finalName>shibboleth-idp-plugin-totp-${project.version}</dist.finalName>
+        <dist.finalName>shibboleth-idp-plugin-${plugin.base}-${project.version}</dist.finalName>
     </properties>
 
     <build>
@@ -36,7 +37,7 @@
                 <configuration>
                     <appendAssemblyId>false</appendAssemblyId>
                     <descriptors>
-                        <descriptor>src/main/assembly/totp-assembly.xml</descriptor>
+                        <descriptor>src/main/assembly/${plugin.base}-assembly.xml</descriptor>
                     </descriptors>
                     <finalName>${dist.finalName}</finalName>
                     <tarLongFileMode>gnu</tarLongFileMode>
diff --git a/totp-dist/src/main/resources/bootstrap/id.property b/totp-dist/src/main/resources/bootstrap/id.property
new file mode 100644
index 0000000..4917477
--- /dev/null
+++ b/totp-dist/src/main/resources/bootstrap/id.property
@@ -0,0 +1 @@
+pluginid=net.shibboleth.idp.plugin.totp
diff --git a/totp-dist/src/main/resources/bootstrap/keys.txt b/totp-dist/src/main/resources/bootstrap/keys.txt
new file mode 100644
index 0000000..0ccc322
--- /dev/null
+++ b/totp-dist/src/main/resources/bootstrap/keys.txt
@@ -0,0 +1,189 @@
+
+pub   4096R/2A4B3FF0 2019-09-18
+uid                  Rod Widdowson <rdw at steadingsoftware.com>
+sub   4096R/441D628D 2019-09-18
+
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+
+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
+HEdQFQ==
+=/gwj
+-----END PGP PUBLIC KEY BLOCK-----
+
+OBS security:shibboleth RPM repository key
+
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+Version: GnuPG v1.4.5 (GNU/Linux)
+
+mQGiBEholYgRBACW/kTYZi5mAEMP8j1qui2bRnWmYblFbiZvb5JMJYUWL/jyMjHj
+LLJvVrnOre/AxexH9KmaJwBuNoa/X9l/tQGIb49QRhR346QQUbQcwlYpckg5ccqN
+qlAURHEdjCxRxMhzPs+C/F6Nqa/fHpAectW0JNRqAVVd9CWjCG3l6I2CywCgk9UI
+SUAvaB5bVMxEVrFAKrVh4MUEAISeUwOaTIZftIamjo0VrnYemHS4SmGqMALEtHeG
+/o7ecMhLb/MvreEVISrE1hbfmnObYoiVXWJrorOEZDh1hOVdGRkHJOYHvQSRp9uC
+/uy4Mmog4R7ba5Ct5wpw0RCav2HMqwOJEyCX6jnip5P5LMmaFdGg/RQZM/e9mbyF
+VeL0A/0WK//+VWrQya1rQIG+v4IZ+rWvrkqXKtrzELkWd/3vWNMXi4BfeBM/itLQ
+yYOdhnx55FHxBzv+dK+UErrdTM8Ingljy7oztV/G6+K15CcGvEy9ITb62v2bDdS2
+uYWEFOQJK+I6aU4paNysvtKsOlTt9FhyfJJW9G3kJDUBPM9HbLRIc2VjdXJpdHk6
+c2hpYmJvbGV0aCBPQlMgUHJvamVjdCA8c2VjdXJpdHk6c2hpYmJvbGV0aEBidWls
+ZC5vcGVuc3VzZS5vcmc+iGYEExECACYFAlgaKTsCGwMFCRPQQ7MGCwkIBwMCBBUC
+CAMEFgIDAQIeAQIXgAAKCRBzyTdFfQobPWC4AJ96FdlQrvlAHzQjqT994h6lZxfZ
+pgCfSBPRhrdNGh72+d288vgZ7ptV4/SIRgQTEQIABgUCSGiViAAKCRA7MBG3a51l
+Iy3vAKCUPurlZup+vzQtpij3FMo0JAVW9ACgjdkt/hWt0WsjfHb+/cPwXtgx9X8=
+=6fV2
+-----END PGP PUBLIC KEY BLOCK-----
+
+Henri Mikkonen PGP key
+
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+
+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
+A+i1fd0Gifis1HhBeA==
+=ObHY
+-----END PGP PUBLIC KEY BLOCK-----
+
+philsmart GPG key 4096-bit RSA key, ID C21771DD, created 2020-02-25
+
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+Version: GnuPG v2.0.22 (GNU/Linux)
+
+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
+3aNjQSVwGC4Owz97QpUq9StZb1qhvIw=
+=1e4x
+-----END PGP PUBLIC KEY BLOCK-----
diff --git a/totp-dist/src/main/resources/doc/GoogleAuth-LICENSE.txt b/totp-dist/src/main/resources/doc/GoogleAuth-LICENSE.txt
new file mode 100644
index 0000000..9c76b45
--- /dev/null
+++ b/totp-dist/src/main/resources/doc/GoogleAuth-LICENSE.txt
@@ -0,0 +1,28 @@
+Copyright (c) 2013 Warren Strange
+Copyright (c) 2014-2017 Enrico M. Crisostomo
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+  * Redistributions of source code must retain the above copyright notice, this
+    list of conditions and the following disclaimer.
+
+  * Redistributions in binary form must reproduce the above copyright notice,
+    this list of conditions and the following disclaimer in the documentation
+    and/or other materials provided with the distribution.
+
+  * Neither the name of the author nor the names of its
+    contributors may be used to endorse or promote products derived from
+    this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
\ No newline at end of file
diff --git a/totp-impl/.checkstyle b/totp-impl/.checkstyle
new file mode 100644
index 0000000..7c63424
--- /dev/null
+++ b/totp-impl/.checkstyle
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<fileset-config file-format-version="1.2.0" simple-config="true" sync-formatter="false">
+  <local-check-config name="Shibboleth Checkstyle" location="/java-idp-plugin-totp/checkstyle.xml" type="project" description="">
+    <additional-data name="protect-config-file" value="false"/>
+  </local-check-config>
+  <fileset name="all" enabled="true" check-config-name="Shibboleth Checkstyle" local="true">
+    <file-match-pattern match-pattern="." include-pattern="true"/>
+  </fileset>
+</fileset-config>
diff --git a/totp-impl/.project b/totp-impl/.project
index 96a82b2..8200b02 100644
--- a/totp-impl/.project
+++ b/totp-impl/.project
@@ -15,9 +15,15 @@
 			<arguments>
 			</arguments>
 		</buildCommand>
+		<buildCommand>
+			<name>net.sf.eclipsecs.core.CheckstyleBuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
 	</buildSpec>
 	<natures>
 		<nature>org.eclipse.jdt.core.javanature</nature>
 		<nature>org.eclipse.m2e.core.maven2Nature</nature>
+		<nature>net.sf.eclipsecs.core.CheckstyleNature</nature>
 	</natures>
 </projectDescription>
diff --git a/totp-impl/pom.xml b/totp-impl/pom.xml
index efb6daa..0a339a4 100644
--- a/totp-impl/pom.xml
+++ b/totp-impl/pom.xml
@@ -6,20 +6,61 @@
 
     <parent>
         <groupId>net.shibboleth.idp.plugin</groupId>
-        <artifactId>java-idp-plugin-totp</artifactId>
+        <artifactId>idp-plugin-totp</artifactId>
         <version>1.0.0-SNAPSHOT</version>
     </parent>
     
     <name>Shibboleth IdP :: Plugins :: TOTP Login Flow Impl</name>
-    <artifactId>idp-plugin-totp-impl</artifactId>
+    <description>IdP TOTP plugin implementation.</description>
+    <artifactId>idp-plugin-${plugin.base}-impl</artifactId>
     <packaging>jar</packaging>
     
     <properties>
         <checkstyle.configLocation>${project.basedir}/../checkstyle.xml</checkstyle.configLocation>
-        <automatic.module.name>net.shibboleth.idp.plugin.totp.impl</automatic.module.name>
+        <automatic.module.name>net.shibboleth.idp.plugin.${plugin.base}.impl</automatic.module.name>
     </properties>
     
     <dependencies>
+        <!-- compile dependencies -->
+        <dependency>
+            <groupId>com.warrenstrange</groupId>
+            <artifactId>googleauth</artifactId>
+            <version>1.5.0</version>
+        </dependency>
+                
+        <!-- provided dependencies -->
+        <dependency>
+            <groupId>net.shibboleth.utilities</groupId>
+            <artifactId>java-support</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>net.shibboleth.ext</groupId>
+            <artifactId>spring-extensions</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>${spring-webflow.groupId}</groupId>
+            <artifactId>spring-webflow</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>${idp.groupId}</groupId>
+            <artifactId>idp-attribute-api</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>${idp.groupId}</groupId>
+            <artifactId>idp-attribute-resolver-api</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>${idp.groupId}</groupId>
+            <artifactId>idp-authn-api</artifactId>
+            <scope>provided</scope>
+        </dependency>
+
+        <!-- test dependencies -->
     </dependencies>
 
     <build>
diff --git a/totp-impl/src/main/java/net/shibboleth/idp/plugin/totp/context/TOTPContext.java b/totp-impl/src/main/java/net/shibboleth/idp/plugin/totp/context/TOTPContext.java
new file mode 100644
index 0000000..6a151d5
--- /dev/null
+++ b/totp-impl/src/main/java/net/shibboleth/idp/plugin/totp/context/TOTPContext.java
@@ -0,0 +1,171 @@
+/*
+ * 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.totp.context;
+
+import java.util.ArrayList;
+import java.util.Collection;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import org.opensaml.messaging.context.BaseContext;
+
+import com.google.common.base.Strings;
+
+import net.shibboleth.utilities.java.support.annotation.constraint.Live;
+import net.shibboleth.utilities.java.support.annotation.constraint.NonnullElements;
+import net.shibboleth.utilities.java.support.annotation.constraint.NotEmpty;
+import net.shibboleth.utilities.java.support.logic.Constraint;
+
+/**
+ * Context class for state of a TOTP validation.
+ */
+public class TOTPContext extends BaseContext {
+
+    /** Transaction status. */
+    public enum AuthState {
+        /** Success. */
+        OK,
+        /** Failure. */
+        ERROR,
+        /** Unable to locate a token registration. */
+        MISSING_SEED,
+        /** No tokens registered. */
+        REGISTER,
+        /** Unable to validate. */
+        CANT_VALIDATE,
+        /** Unknown. */
+        UNKNOWN,
+    }
+
+    /** State of transaction. */
+    @Nonnull private AuthState state;
+
+    /** The subject identifier with respect to the token "back-end". */
+    @Nullable @NotEmpty private String username;
+
+    /** The token code supplied. */
+    @Nullable private Integer tokenCode;
+
+    /** The token seeds associated with the subject. */
+    @Nonnull @NonnullElements private Collection<String> tokenSeeds;
+    
+    /** URL for QR-code. */
+    @Nullable @NotEmpty private String totpURL;
+
+    /** Constructor. */
+    public TOTPContext() {
+        state = AuthState.UNKNOWN;
+        tokenSeeds = new ArrayList<>();
+    }
+
+    /**
+     * Get the state of the transaction.
+     * 
+     * @return transaction state
+     */
+    @Nonnull public AuthState getState() {
+        return state;
+    }
+
+    
+    /**
+     * Set the state of the transaction.
+     * 
+     * @param astate new state
+     * 
+     * @return this context
+     */
+    @Nonnull public TOTPContext setState(@Nonnull final AuthState astate) {
+      state = Constraint.isNotNull(astate, "AuthState cannot be null");
+      
+      return this;
+    }
+
+    /**
+     * Get the username.
+     *
+     * @return the username
+     */
+    @Nullable @NotEmpty public String getUsername() {
+        return username;
+    }
+
+    /**
+     * Set the username.
+     *
+     * @param name the username
+     *
+     * @return this context
+     */
+    @Nonnull public TOTPContext setUsername(@Nullable @NotEmpty final String name) {
+        if (Strings.isNullOrEmpty(name)) {
+            username = null;
+        } else {
+            username = name;
+        }
+        
+        return this;
+    }
+
+    /**
+     * Get the token code.
+     *
+     * @return the token code
+     */
+    @Nullable public Integer getTokenCode() {
+        return tokenCode;
+    }
+
+    /**
+     * Set the token code.
+     *
+     * @param code the token code
+     *
+     * @return this context
+     */
+    @Nonnull public TOTPContext setTokenCode(@Nullable final Integer code) {
+        tokenCode = code;
+        
+        return this;
+    }
+
+    /**
+     * Get the token seeds for the subject.
+     *
+     * @return the token seeds
+     */
+     @Nonnull @NonnullElements @Live public Collection<String> getTokenSeeds() {
+         return tokenSeeds;
+     }
+
+     /*
+      //A counter for the numbers of times the user has failed auth in this context
+      private int failedAuth = 0;
+    
+    
+      public void failedAttempt() {
+        failedAuth++;
+      }
+    
+      public int getFailedAttempts(){
+        return failedAuth;
+      }
+    */
+
+}
\ No newline at end of file
diff --git a/totp-impl/src/main/java/net/shibboleth/idp/plugin/totp/context/package-info.java b/totp-impl/src/main/java/net/shibboleth/idp/plugin/totp/context/package-info.java
new file mode 100644
index 0000000..11e523f
--- /dev/null
+++ b/totp-impl/src/main/java/net/shibboleth/idp/plugin/totp/context/package-info.java
@@ -0,0 +1,20 @@
+/*
+ * 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.
+ */
+
+/** TOTP login flow context classes. */
+
+package net.shibboleth.idp.plugin.totp.context;
diff --git a/totp-impl/src/main/java/net/shibboleth/idp/plugin/totp/impl/AbstractSeedSource.java b/totp-impl/src/main/java/net/shibboleth/idp/plugin/totp/impl/AbstractSeedSource.java
new file mode 100644
index 0000000..69c116a
--- /dev/null
+++ b/totp-impl/src/main/java/net/shibboleth/idp/plugin/totp/impl/AbstractSeedSource.java
@@ -0,0 +1,73 @@
+/*
+ * 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.totp.impl;
+
+import java.util.function.Consumer;
+import java.util.function.Function;
+
+import javax.annotation.Nonnull;
+
+import org.opensaml.messaging.context.navigate.ChildContextLookup;
+import org.opensaml.profile.context.ProfileRequestContext;
+
+import net.shibboleth.idp.authn.context.AuthenticationContext;
+import net.shibboleth.idp.plugin.totp.context.TOTPContext;
+import net.shibboleth.utilities.java.support.annotation.constraint.ThreadSafeAfterInit;
+import net.shibboleth.utilities.java.support.component.AbstractInitializableComponent;
+import net.shibboleth.utilities.java.support.component.ComponentSupport;
+import net.shibboleth.utilities.java.support.logic.Constraint;
+import net.shibboleth.utilities.java.support.logic.FunctionSupport;
+
+/**
+ * Base class for token seed source implementations.
+ */
+ at ThreadSafeAfterInit
+public abstract class AbstractSeedSource extends AbstractInitializableComponent
+        implements Consumer<ProfileRequestContext> {
+
+    /** Lookup strategy for {@link TOTPContext}. */
+    @Nonnull private Function<ProfileRequestContext,TOTPContext> totpContextLookupStrategy;
+
+    /** Constructor. */
+    public AbstractSeedSource() {
+        // PRC -> AuthenticationContext -> TOTPContext
+        totpContextLookupStrategy = FunctionSupport.compose(new ChildContextLookup<>(TOTPContext.class),
+                new ChildContextLookup<>(AuthenticationContext.class));
+    }
+
+    /**
+     * Get the {@link TOTPContext} lookup strategy.
+     * 
+     * @return lookup strategy
+     */
+    @Nonnull public Function<ProfileRequestContext,TOTPContext> getTOTPContextLookupStrategy() {
+        return totpContextLookupStrategy;
+    }
+
+    /**
+     * Set the {@link TOTPContext} lookup strategy.
+     * 
+     * @param strategy lookup strategy
+     */
+    public void setTOTPContextLookupStrategy(@Nonnull final Function<ProfileRequestContext,TOTPContext> strategy) {
+        ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
+        
+        totpContextLookupStrategy = Constraint.isNotNull(strategy, "Lookup strategy cannot be null");
+    }
+
+}
\ No newline at end of file
diff --git a/totp-impl/src/main/java/net/shibboleth/idp/plugin/totp/impl/AttributeResolverSeedSource.java b/totp-impl/src/main/java/net/shibboleth/idp/plugin/totp/impl/AttributeResolverSeedSource.java
new file mode 100644
index 0000000..94ca139
--- /dev/null
+++ b/totp-impl/src/main/java/net/shibboleth/idp/plugin/totp/impl/AttributeResolverSeedSource.java
@@ -0,0 +1,133 @@
+/*
+ * 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.totp.impl;
+
+import java.util.Collection;
+import java.util.Collections;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import org.opensaml.profile.context.ProfileRequestContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import net.shibboleth.idp.attribute.IdPAttribute;
+import net.shibboleth.idp.attribute.StringAttributeValue;
+import net.shibboleth.idp.attribute.resolver.AttributeResolver;
+import net.shibboleth.idp.attribute.resolver.context.AttributeResolutionContext;
+import net.shibboleth.idp.plugin.totp.context.TOTPContext;
+import net.shibboleth.utilities.java.support.annotation.constraint.NonnullAfterInit;
+import net.shibboleth.utilities.java.support.annotation.constraint.NotEmpty;
+import net.shibboleth.utilities.java.support.annotation.constraint.ThreadSafeAfterInit;
+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 net.shibboleth.utilities.java.support.service.ReloadableService;
+
+/**
+ * Token seed source implementation that leverages the {@link AttributeResolver}.
+ */
+ at ThreadSafeAfterInit
+public class AttributeResolverSeedSource extends AbstractSeedSource {
+
+    /** Class logger. */
+    @Nonnull private final Logger log = LoggerFactory.getLogger(AttributeResolverSeedSource.class);
+    
+    /** Attribute resolver service. */
+    @NonnullAfterInit private ReloadableService<AttributeResolver> attributeResolver;
+    
+    /** Attribute ID to resolve. */
+    @NonnullAfterInit @NotEmpty private String attributeId;
+    
+    
+    /**
+     * Set the {@link AttributeResolver} to use.
+     * 
+     * @param service the resolver
+     */
+    public void setAttributeResolver(@Nonnull final ReloadableService<AttributeResolver> service) {
+        ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
+        
+        attributeResolver = Constraint.isNotNull(service, "AttributeResolver cannot be null");
+    }
+    
+    /**
+     * Set the source attribute ID to resolve.
+     * 
+     * @param id attribute ID
+     */
+    public void setSourceAttribute(@Nonnull @NotEmpty final String id) {
+        ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
+        
+        attributeId = Constraint.isNotNull(StringSupport.trimOrNull(id), "Source attribute ID cannot be null or empty");
+    }
+    
+    /** {@inheritDoc} */
+    @Override
+    protected void doInitialize() throws ComponentInitializationException {
+        super.doInitialize();
+        
+        if (attributeResolver == null) {
+            throw new ComponentInitializationException("AttributeResolver cannot be null");
+        } else if (attributeId == null) {
+            throw new ComponentInitializationException("Source attribute ID cannot be null");
+        }
+    }
+
+    /** {@inheritDoc} */
+    public void accept(@Nullable final ProfileRequestContext input) {
+        ComponentSupport.ifNotInitializedThrowUninitializedComponentException(this);
+        
+        final TOTPContext totp = getTOTPContextLookupStrategy().apply(input);
+        if (totp != null && totp.getUsername() != null) {
+            final AttributeResolutionContext resCtx = totp.getSubcontext(AttributeResolutionContext.class, true);
+
+            resCtx.setResolutionLabel("TOTP");
+            resCtx.setPrincipal(totp.getUsername());
+            resCtx.setRequestedIdPAttributeNames(Collections.singletonList(attributeId));
+
+            log.debug("Resolving attribute {} for '{}'", attributeId, totp.getUsername());
+
+            final Collection<String> seeds = totp.getTokenSeeds();
+
+            try {
+                // Resolve the attributes.
+                resCtx.resolveAttributes(attributeResolver);
+    
+                final IdPAttribute attribute = resCtx.getResolvedIdPAttributes().get(attributeId);
+                if (attribute != null) {                    
+                    attribute.getValues()
+                        .stream()
+                        .filter(StringAttributeValue.class::isInstance)
+                        .map(StringAttributeValue.class::cast)
+                        .map(StringAttributeValue::getValue)
+                        .forEachOrdered(seeds::add);
+                }
+            } finally {
+                totp.removeSubcontext(resCtx);
+            }
+
+            log.debug("Resolved {} seed(s) for '{}'", seeds.size(), totp.getUsername());
+        } else {
+            log.warn("Unable to locate TOTPContext and username");
+        }
+    }
+
+}
\ No newline at end of file
diff --git a/totp-impl/src/main/java/net/shibboleth/idp/plugin/totp/impl/StaticSeedSource.java b/totp-impl/src/main/java/net/shibboleth/idp/plugin/totp/impl/StaticSeedSource.java
new file mode 100644
index 0000000..c23eca7
--- /dev/null
+++ b/totp-impl/src/main/java/net/shibboleth/idp/plugin/totp/impl/StaticSeedSource.java
@@ -0,0 +1,90 @@
+/*
+ * 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.totp.impl;
+
+import java.util.Collection;
+import java.util.Map;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import org.opensaml.profile.context.ProfileRequestContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.collect.LinkedListMultimap;
+import com.google.common.collect.Multimap;
+
+import net.shibboleth.idp.plugin.totp.context.TOTPContext;
+import net.shibboleth.utilities.java.support.annotation.constraint.NonnullElements;
+import net.shibboleth.utilities.java.support.annotation.constraint.ThreadSafeAfterInit;
+import net.shibboleth.utilities.java.support.component.ComponentSupport;
+import net.shibboleth.utilities.java.support.logic.Constraint;
+import net.shibboleth.utilities.java.support.primitive.StringSupport;
+
+/**
+ * Token seed source implementation that returns statically defined values.
+ */
+ at ThreadSafeAfterInit
+public class StaticSeedSource extends AbstractSeedSource {
+
+    /** Class logger. */
+    @Nonnull private final Logger log = LoggerFactory.getLogger(StaticSeedSource.class);
+    
+    /** Token seeds. */
+    @Nonnull @NonnullElements private Multimap<String,String> tokenSeeds;
+    
+    /** Constructor. */
+    public StaticSeedSource() {
+        tokenSeeds = LinkedListMultimap.create();
+    }
+    
+    /**
+     * Set static token seeds, keyed by username.
+     * 
+     * @param seeds the seeds
+     */
+    public void setSeeds(@Nonnull @NonnullElements final Map<String,Collection<String>> seeds) {
+        ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
+        Constraint.isNotNull(seeds, "Seed map cannot be null");
+        
+        seeds.forEach((k,v) -> {
+            final String user = StringSupport.trimOrNull(k);
+            if (user != null) {
+                tokenSeeds.putAll(user, StringSupport.normalizeStringCollection(v));
+            }
+        });
+    }
+    
+    /** {@inheritDoc} */
+    public void accept(@Nullable final ProfileRequestContext input) {
+        ComponentSupport.ifNotInitializedThrowUninitializedComponentException(this);
+        
+        final TOTPContext totp = getTOTPContextLookupStrategy().apply(input);
+        if (totp != null) {
+            if (totp.getUsername() != null) {
+                totp.getTokenSeeds().addAll(tokenSeeds.get(totp.getUsername()));
+            } else {
+                log.warn("TOTPContext did not contain a username");
+            }
+        } else {
+            log.warn("Unable to locate TOTPContext");
+        }
+    }
+
+}
\ No newline at end of file
diff --git a/totp-impl/src/main/java/net/shibboleth/idp/plugin/totp/principal/TOTPPrincipal.java b/totp-impl/src/main/java/net/shibboleth/idp/plugin/totp/principal/TOTPPrincipal.java
new file mode 100644
index 0000000..a746f74
--- /dev/null
+++ b/totp-impl/src/main/java/net/shibboleth/idp/plugin/totp/principal/TOTPPrincipal.java
@@ -0,0 +1,89 @@
+/*
+ * 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.totp.principal;
+
+import javax.annotation.Nonnull;
+
+import net.shibboleth.idp.authn.principal.CloneablePrincipal;
+import net.shibboleth.utilities.java.support.annotation.ParameterName;
+import net.shibboleth.utilities.java.support.annotation.constraint.NotEmpty;
+import net.shibboleth.utilities.java.support.logic.Constraint;
+import net.shibboleth.utilities.java.support.primitive.StringSupport;
+
+import com.google.common.base.MoreObjects;
+
+/** Principal based on a TOTP authentication. */
+public class TOTPPrincipal implements CloneablePrincipal {
+
+    /** The username. */
+    @Nonnull @NotEmpty private String username;
+
+    /**
+     * Constructor.
+     * 
+     * @param name the username
+     */
+    public TOTPPrincipal(@Nonnull @NotEmpty @ParameterName(name="name") final String name) {
+        username = Constraint.isNotNull(StringSupport.trimOrNull(name), "Username cannot be null or empty");
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    @Nonnull @NotEmpty public String getName() {
+        return username;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int hashCode() {
+        return username.hashCode();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean equals(final Object other) {
+        if (other == null) {
+            return false;
+        }
+
+        if (this == other) {
+            return true;
+        }
+
+        if (other instanceof TOTPPrincipal) {
+            return username.equals(((TOTPPrincipal) other).getName());
+        }
+
+        return false;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String toString() {
+        return MoreObjects.toStringHelper(this).add("username", username).toString();
+    }
+    
+    /** {@inheritDoc} */
+    @Override
+    public TOTPPrincipal clone() throws CloneNotSupportedException {
+        final TOTPPrincipal copy = (TOTPPrincipal) super.clone();
+        copy.username = username;
+        return copy;
+    }
+    
+}
\ No newline at end of file
diff --git a/totp-impl/src/main/java/net/shibboleth/idp/plugin/totp/principal/package-info.java b/totp-impl/src/main/java/net/shibboleth/idp/plugin/totp/principal/package-info.java
new file mode 100644
index 0000000..ce752fa
--- /dev/null
+++ b/totp-impl/src/main/java/net/shibboleth/idp/plugin/totp/principal/package-info.java
@@ -0,0 +1,22 @@
+/*
+ * 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.
+ */
+
+/**
+ * Custom TOTP principal types.
+ */
+
+package net.shibboleth.idp.plugin.totp.principal;
\ 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