[java-idp-plugin-totp] branch master updated: Bug fixing and error handling changes, initial views and messages.

Scott Cantor cantor.2 at osu.edu
Thu Aug 6 17:30:12 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=65e6ceb0af37ddb2cc96aed42a7d0cfcf07881c4

The following commit(s) were added to refs/heads/master by this push:
       new  65e6ceb   Bug fixing and error handling changes, initial views and messages.
65e6ceb is described below

commit 65e6ceb0af37ddb2cc96aed42a7d0cfcf07881c4
Author: Scott Cantor <cantor.2 at osu.edu>
AuthorDate: Thu Aug 6 13:31:29 2020 -0400

    Bug fixing and error handling changes, initial views and messages.
---
 .../totp/impl/AbstractTOTPCredentialValidator.java |  16 ++--
 .../totp/impl/AbstractTOTPExtractionAction.java    |  24 ++++-
 .../totp/impl/AttributeResolverSeedSource.java     |   3 +
 .../totp/impl/ExtractTOTPFromFormRequest.java      |  15 +--
 .../plugin/totp/impl/ExtractTOTPFromHeader.java    |  15 +--
 .../{totp/totp-beans.xml => TOTP/TOTP-beans.xml}   |  22 +++--
 .../{totp/totp-flow.xml => TOTP/TOTP-flow.xml}     |  36 ++++---
 .../shibboleth/idp/plugin/totp/messages.properties |  13 +++
 totp-impl/src/main/resources/views/totp-error.vm   |  31 +++++++
 totp-impl/src/main/resources/views/totp.vm         | 103 +++++++++++++++++++++
 .../totp/impl/ExtractTOTPFromFormRequestTest.java  |   5 +-
 .../totp/impl/ExtractTOTPFromHeaderTest.java       |   5 +-
 ...GoogleAuthenticatorCredentialValidatorTest.java |   4 +-
 13 files changed, 229 insertions(+), 63 deletions(-)

diff --git a/totp-impl/src/main/java/net/shibboleth/idp/plugin/totp/impl/AbstractTOTPCredentialValidator.java b/totp-impl/src/main/java/net/shibboleth/idp/plugin/totp/impl/AbstractTOTPCredentialValidator.java
index b331029..d97edd9 100644
--- a/totp-impl/src/main/java/net/shibboleth/idp/plugin/totp/impl/AbstractTOTPCredentialValidator.java
+++ b/totp-impl/src/main/java/net/shibboleth/idp/plugin/totp/impl/AbstractTOTPCredentialValidator.java
@@ -128,24 +128,24 @@ public abstract class AbstractTOTPCredentialValidator extends AbstractCredential
         if (totpContext == null) {
             log.info("{} No TOTPContext available", getLogPrefix());
             if (errorHandler != null) {
-                errorHandler.handleError(profileRequestContext, authenticationContext, (String) null,
+                errorHandler.handleError(profileRequestContext, authenticationContext, AuthnEventIds.NO_CREDENTIALS,
                         AuthnEventIds.NO_CREDENTIALS);
             }
             throw new LoginException(AuthnEventIds.NO_CREDENTIALS);
         } else if (totpContext.getUsername() == null) {
             log.info("{} No username available within TOTPContext", getLogPrefix());
             if (errorHandler != null) {
-                errorHandler.handleError(profileRequestContext, authenticationContext, (String) null,
-                        AuthnEventIds.NO_CREDENTIALS);
+                errorHandler.handleError(profileRequestContext, authenticationContext, AuthnEventIds.UNKNOWN_USERNAME,
+                        AuthnEventIds.UNKNOWN_USERNAME);
             }
             throw new LoginException(AuthnEventIds.NO_CREDENTIALS);
         } else if (totpContext.getTokenCode() == null) {
             log.info("{} No tokencode available within TOTPContext", getLogPrefix());
             if (errorHandler != null) {
-                errorHandler.handleError(profileRequestContext, authenticationContext, (String) null,
-                        AuthnEventIds.INVALID_CREDENTIALS);
+                errorHandler.handleError(profileRequestContext, authenticationContext, AuthnEventIds.NO_CREDENTIALS,
+                        AuthnEventIds.NO_CREDENTIALS);
             }
-            throw new LoginException(AuthnEventIds.INVALID_CREDENTIALS);
+            throw new LoginException(AuthnEventIds.NO_CREDENTIALS);
         }
         
         if (totpContext.getTokenSeeds().isEmpty()) {
@@ -155,8 +155,8 @@ public abstract class AbstractTOTPCredentialValidator extends AbstractCredential
             if (totpContext.getTokenSeeds().isEmpty()) {
                 log.info("{} No seeds were obtained for user '{}'", getLogPrefix(), totpContext.getUsername());
                 if (errorHandler != null) {
-                    errorHandler.handleError(profileRequestContext, authenticationContext, (String) null,
-                            AuthnEventIds.INVALID_CREDENTIALS);
+                    errorHandler.handleError(profileRequestContext, authenticationContext,
+                            AuthnEventIds.INVALID_CREDENTIALS, AuthnEventIds.INVALID_CREDENTIALS);
                 }
                 throw new LoginException(AuthnEventIds.INVALID_CREDENTIALS);
             }
diff --git a/totp-impl/src/main/java/net/shibboleth/idp/plugin/totp/impl/AbstractTOTPExtractionAction.java b/totp-impl/src/main/java/net/shibboleth/idp/plugin/totp/impl/AbstractTOTPExtractionAction.java
index 9c9ec1d..e6a6121 100644
--- a/totp-impl/src/main/java/net/shibboleth/idp/plugin/totp/impl/AbstractTOTPExtractionAction.java
+++ b/totp-impl/src/main/java/net/shibboleth/idp/plugin/totp/impl/AbstractTOTPExtractionAction.java
@@ -26,6 +26,7 @@ import javax.servlet.http.HttpServletRequest;
 import net.shibboleth.idp.authn.AbstractAuthenticationAction;
 import net.shibboleth.idp.authn.AuthnEventIds;
 import net.shibboleth.idp.authn.context.AuthenticationContext;
+import net.shibboleth.idp.authn.context.AuthenticationErrorContext;
 import net.shibboleth.idp.plugin.totp.context.TOTPContext;
 import net.shibboleth.idp.session.context.navigate.CanonicalUsernameLookupStrategy;
 import net.shibboleth.utilities.java.support.component.ComponentSupport;
@@ -44,7 +45,10 @@ import org.slf4j.LoggerFactory;
  * 
  * @event {@link org.opensaml.profile.action.EventIds#PROCEED_EVENT_ID}
  * @event {@link AuthnEventIds#NO_CREDENTIALS}
- * @pre <pre>ProfileRequestContext.getSubcontext(AuthenticationContext.class, false) != null</pre>
+ * @event {@link AuthnEventIds#UNKNOWN_USERNAME}
+ * @event {@link AuthnEventIds#INVALID_CREDENTIALS}
+ * @pre <pre>ProfileRequestContext.getSubcontext(AuthenticationContext.class) != null</pre>
+ * @post <pre>AuthenticationContext.getSubcontext(TOTPContext.class) != null</pre>
  */
 public abstract class AbstractTOTPExtractionAction extends AbstractAuthenticationAction {
 
@@ -93,6 +97,9 @@ public abstract class AbstractTOTPExtractionAction extends AbstractAuthenticatio
     protected void doExecute(@Nonnull final ProfileRequestContext profileRequestContext,
             @Nonnull final AuthenticationContext authenticationContext) {
 
+        // Clear error state.
+        authenticationContext.removeSubcontext(AuthenticationErrorContext.class);
+        
         totpContext = totpContextCreationStrategy.apply(authenticationContext);
         totpContext.setTokenCode(null);
         
@@ -101,7 +108,7 @@ public abstract class AbstractTOTPExtractionAction extends AbstractAuthenticatio
             final String username = usernameLookupStrategy.apply(profileRequestContext);
             if (username == null) {
                 log.warn("{} No principal name available", getLogPrefix());
-                ActionSupport.buildEvent(profileRequestContext, AuthnEventIds.NO_CREDENTIALS);
+                ActionSupport.buildEvent(profileRequestContext, AuthnEventIds.UNKNOWN_USERNAME);
                 return;
             }
             totpContext.setUsername(username);
@@ -114,13 +121,20 @@ public abstract class AbstractTOTPExtractionAction extends AbstractAuthenticatio
             return;
         }
         
-        final Integer code = extractCode(request);
+        final String code = extractCode(request);
         if (code == null) {
             ActionSupport.buildEvent(profileRequestContext, AuthnEventIds.NO_CREDENTIALS);
             return;
         }
         
-        totpContext.setTokenCode(code);
+        try {
+            totpContext.setTokenCode(Integer.valueOf(code));
+        } catch (final NumberFormatException e) {
+            log.warn("{} Exception converting code string to an integer", getLogPrefix(), e);
+            authenticationContext.getSubcontext(AuthenticationErrorContext.class,
+                    true).getClassifiedErrors().add(AuthnEventIds.INVALID_CREDENTIALS);
+            ActionSupport.buildEvent(profileRequestContext, AuthnEventIds.INVALID_CREDENTIALS);
+        }
     }
 
     /**
@@ -130,6 +144,6 @@ public abstract class AbstractTOTPExtractionAction extends AbstractAuthenticatio
      * 
      * @return the token code, or null
      */
-    @Nullable protected abstract Integer extractCode(@Nonnull final HttpServletRequest httpRequest);
+    @Nullable protected abstract String extractCode(@Nonnull final HttpServletRequest httpRequest);
     
 }
\ 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
index c0f4c2e..011ee0a 100644
--- 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
@@ -47,6 +47,9 @@ import net.shibboleth.utilities.java.support.service.ReloadableService;
 @ThreadSafeAfterInit
 public class AttributeResolverSeedSource extends AbstractSeedSource {
 
+    /** Default attribute ID source. */
+    @Nonnull @NotEmpty public static final String DEFAULT_ATTRIBUTE_ID = "tokenSeeds";
+    
     /** Class logger. */
     @Nonnull private final Logger log = LoggerFactory.getLogger(AttributeResolverSeedSource.class);
     
diff --git a/totp-impl/src/main/java/net/shibboleth/idp/plugin/totp/impl/ExtractTOTPFromFormRequest.java b/totp-impl/src/main/java/net/shibboleth/idp/plugin/totp/impl/ExtractTOTPFromFormRequest.java
index 622f0a2..068db9a 100644
--- a/totp-impl/src/main/java/net/shibboleth/idp/plugin/totp/impl/ExtractTOTPFromFormRequest.java
+++ b/totp-impl/src/main/java/net/shibboleth/idp/plugin/totp/impl/ExtractTOTPFromFormRequest.java
@@ -62,19 +62,8 @@ public class ExtractTOTPFromFormRequest extends AbstractTOTPExtractionAction {
 
     /** {@inheritDoc} */
     @Override
-    @Nullable protected Integer extractCode(@Nonnull final HttpServletRequest httpRequest) {
-        final String code = httpRequest.getParameter(fieldName);
-        if (code != null) {
-            try {
-                return Integer.valueOf(code);
-            } catch (final NumberFormatException e) {
-                log.warn("{} Exception converting parameter value to integer code", getLogPrefix(), e);
-            }
-        } else {
-            log.trace("{} Token code field {} not found", getLogPrefix(), fieldName);
-        }
-        
-        return null;
+    @Nullable protected String extractCode(@Nonnull final HttpServletRequest httpRequest) {
+        return httpRequest.getParameter(fieldName);
     }
     
 }
\ No newline at end of file
diff --git a/totp-impl/src/main/java/net/shibboleth/idp/plugin/totp/impl/ExtractTOTPFromHeader.java b/totp-impl/src/main/java/net/shibboleth/idp/plugin/totp/impl/ExtractTOTPFromHeader.java
index d07fc0f..e99235e 100644
--- a/totp-impl/src/main/java/net/shibboleth/idp/plugin/totp/impl/ExtractTOTPFromHeader.java
+++ b/totp-impl/src/main/java/net/shibboleth/idp/plugin/totp/impl/ExtractTOTPFromHeader.java
@@ -62,19 +62,8 @@ public class ExtractTOTPFromHeader extends AbstractTOTPExtractionAction {
 
     /** {@inheritDoc} */
     @Override
-    @Nullable protected Integer extractCode(@Nonnull final HttpServletRequest httpRequest) {
-        final String code = httpRequest.getHeader(headerName);
-        if (code != null) {
-            try {
-                return Integer.valueOf(code);
-            } catch (final NumberFormatException e) {
-                log.warn("{} Exception converting header value to integer code", getLogPrefix(), e);
-            }
-        } else {
-            log.trace("{} Token code header {} not found", getLogPrefix(), headerName);
-        }
-        
-        return null;
+    @Nullable protected String extractCode(@Nonnull final HttpServletRequest httpRequest) {
+        return httpRequest.getHeader(headerName);
     }
     
 }
\ No newline at end of file
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
similarity index 81%
rename from totp-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/authn/totp/totp-beans.xml
rename to totp-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/authn/TOTP/TOTP-beans.xml
index 900b39c..4a9cdfd 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
@@ -18,6 +18,11 @@
     <bean class="net.shibboleth.ext.spring.config.IdentifiableBeanPostProcessor" />
     <bean class="net.shibboleth.idp.profile.impl.ProfileActionBeanPostProcessor" />
 
+    <bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource"
+            p:cacheSeconds="%{idp.message.cacheSeconds:300}"
+            p:basenames="classpath:/net/shibboleth/idp/plugin/totp/messages"
+            p:defaultEncoding="UTF-8" />
+
     <import resource="conditional:%{idp.home}/conf/authn/totp-authn-config.xml" />
 
     <bean id="ExtractTOTPFromHeader"
@@ -33,18 +38,23 @@
     <bean id="ValidateTOTPCredentials"
         class="net.shibboleth.idp.authn.impl.ValidateCredentials" scope="prototype"
         p:validators="#{getObject('shibboleth.authn.TOTP.Validator') ?: getObject('DefaultTOTPValidator')}"
-        p:addDefaultPrincipals="#{getObject('shibboleth.authn.TOTP.addDefaultPrincipals') ?:
-            (getObject('shibboleth.authn.TOTP.PrincipalOverride') == null
-                or getObject('shibboleth.authn.TOTP.PrincipalOverride').isEmpty())}"
-        p:supportedPrincipals="#{getObject('shibboleth.authn.TOTP.PrincipalOverride')}"
-        p:classifiedMessages-ref="shibboleth.authn.TOTP.ClassifiedMessageMap"
         p:resultCachingPredicate="#{getObject('shibboleth.authn.TOTP.resultCachingPredicate')}"
+        p:classifiedMessages-ref="TOTPClassifiedMessageMap"
         p:lockoutManager="#{getObject('shibboleth.authn.TOTP.AccountLockoutManager')}" />
     
+    <util:map id="TOTPClassifiedMessageMap">
+        <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.totp.impl.GoogleAuthenticatorCredentialValidator" lazy-init="true"
-        p:matchExpression="#{getObject('shibboleth.authn.TOTP.matchExpression')}" />
+        p:matchExpression="#{getObject('shibboleth.authn.TOTP.matchExpression')}"
+        p:seedSource="#{getObject('shibboleth.authn.TOTP.SeedSource') ?: getObject('DefaultSeedSource')}" />
         
     <bean id="DefaultSeedSource" class="net.shibboleth.idp.plugin.totp.impl.AttributeResolverSeedSource" lazy-init="true"
         p:attributeResolver-ref="shibboleth.AttributeResolverService"
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
similarity index 60%
rename from totp-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/authn/totp/totp-flow.xml
rename to totp-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/authn/TOTP/TOTP-flow.xml
index 153b84e..76428a6 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
@@ -10,15 +10,12 @@
         <evaluate expression="'proceed'" />
 
         <transition on="proceed" to="ValidateTOTPCredentials" />
-        <transition on="NoCredentials" to="ExtractTOTPFromFormRequest" />
-    </action-state>
 
-    <!-- Then check for propagation via password (or other) form. -->
-    <action-state id="ExtractTOTPFromFormRequest">
-        <evaluate expression="ExtractTOTPFromFormRequest" />
-        <evaluate expression="'proceed'" />
+        <!-- Fall through to a different flow if header extract fails on a passive or non-browser request. -->
+        <transition on="#{ opensamlProfileRequestContext.getSubcontext(T(net.shibboleth.idp.authn.context.AuthenticationContext)).isPassive() || !opensamlProfileRequestContext.isBrowserProfile() }" to="ReselectFlow" />
 
-        <transition on="proceed" to="ValidateTOTPCredentials" />
+        <transition on="UnknownUsername" to="ReselectFlow" />
+        <transition on="InvalidCredentials" to="DisplayTOTPView" />
         <transition on="NoCredentials" to="DisplayTOTPView" />
     </action-state>
 
@@ -26,8 +23,10 @@
 		<on-render>
 			<evaluate expression="environment" result="viewScope.environment" />
 			<evaluate expression="opensamlProfileRequestContext" result="viewScope.profileRequestContext" />
-			<evaluate expression="opensamlProfileRequestContext.getSubcontext(T(net.shibboleth.idp.authn.context.AuthenticationContext))"
-				result="viewScope.authenticationContext" />
+			<evaluate expression="opensamlProfileRequestContext.getSubcontext(T(net.shibboleth.idp.authn.context.AuthenticationContext))" result="viewScope.authenticationContext" />
+            <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.getExternalContext().getNativeRequest()" result="viewScope.request" />
 			<evaluate expression="flowRequestContext.getExternalContext().getNativeResponse()" result="viewScope.response" />
@@ -38,15 +37,28 @@
 		<transition on="proceed" to="ExtractTOTPFromFormRequest" />
 	</view-state>
 
+    <!-- Then check for propagation via password (or other) form. -->
+    <action-state id="ExtractTOTPFromFormRequest">
+        <evaluate expression="ExtractTOTPFromFormRequest" />
+        <evaluate expression="'proceed'" />
+
+        <transition on="proceed" to="ValidateTOTPCredentials" />
+        <transition on="UnknownUsername" to="ReselectFlow" />
+        <transition on="InvalidCredentials" to="DisplayTOTPView" />
+        <transition on="NoCredentials" to="DisplayTOTPView" />
+    </action-state>
+
+
 	<action-state id="ValidateTOTPCredentials">
 		<evaluate expression="ValidateTOTPCredentials" />
 		<evaluate expression="'proceed'" />
 
         <transition on="proceed" to="proceed" />
-		<transition on="InvalidCredentials" to="DisplayTOTPView" />
-		<transition on="NoCredentials" to="DisplayTOTPView" />
+        <transition on="UnknownUsername" to="ReselectFlow" />
+        <transition on="NoCredentials" to="DisplayTOTPView" />
+        <transition on="InvalidCredentials" to="DisplayTOTPView" />
 	</action-state>
 
-	<bean-import resource="totp-beans.xml" />
+	<bean-import resource="TOTP-beans.xml" />
 
 </flow>
diff --git a/totp-impl/src/main/resources/net/shibboleth/idp/plugin/totp/messages.properties b/totp-impl/src/main/resources/net/shibboleth/idp/plugin/totp/messages.properties
new file mode 100644
index 0000000..4f3f24e
--- /dev/null
+++ b/totp-impl/src/main/resources/net/shibboleth/idp/plugin/totp/messages.properties
@@ -0,0 +1,13 @@
+# In addition to the Apache 2.0 license, this content is also licensed
+# under the Creative Commons Attribution-ShareAlike 3.0 Unported license
+# (see http://creativecommons.org/licenses/by-sa/3.0/). 
+
+# This is the as-delivered set of messages used in various views
+# so that internationalized translations can be made available and
+# so administrators can locally override or supplement the values
+# in their own message files.
+
+
+idp.totp.field = Token Code
+
+bad-tokencode.message = The supplied token code was invalid.
diff --git a/totp-impl/src/main/resources/views/totp-error.vm b/totp-impl/src/main/resources/views/totp-error.vm
new file mode 100644
index 0000000..388db80
--- /dev/null
+++ b/totp-impl/src/main/resources/views/totp-error.vm
@@ -0,0 +1,31 @@
+## Velocity Template for TOTP error message production, included by totp.vm
+##
+## authenticationErrorContext - context containing error data, if available
+##
+#if ($authenticationErrorContext && $authenticationErrorContext.getClassifiedErrors().size() > 0)
+    ## This handles errors that are classified by the message maps in the authentication config.
+    #set ($eventId = $authenticationErrorContext.getClassifiedErrors().iterator().next())
+    #if ($eventId != "ReselectFlow")
+        #set ($eventKey = $springMacroRequestContext.getMessage("$eventId", "login"))
+        #set ($message = $springMacroRequestContext.getMessage("${eventKey}.message", "Login Failure: $eventId"))
+    #end
+#elseif ($authenticationErrorContext && $authenticationErrorContext.getExceptions().size() > 0)
+    ## This handles login exceptions that are left unclassified.
+    #set ($loginException = $authenticationErrorContext.getExceptions().get(0))
+    #if ($loginException.getMessage())
+        #set ($message = "Login Failure: $loginException.getMessage()")
+    #else
+    	#set ($message = $loginException.toString())
+    #end
+#elseif ($flowRequestContext)
+    #set ($eventId = $flowRequestContext.getCurrentEvent().getId())
+    #if ($eventId == "InvalidCredentials")
+        #set ($message = $springMacroRequestContext.getMessage("idp.totp.invalid", "The supplied token code was invalid."))
+    #end
+#end
+
+#if ($message)
+    <section>
+        <p class="form-element form-error">$encoder.encodeForHTML($message)</p>
+    </section>
+#end
diff --git a/totp-impl/src/main/resources/views/totp.vm b/totp-impl/src/main/resources/views/totp.vm
new file mode 100644
index 0000000..b3bde33
--- /dev/null
+++ b/totp-impl/src/main/resources/views/totp.vm
@@ -0,0 +1,103 @@
+##
+## Velocity Template for DisplayTOTPView view-state
+##
+## Velocity context will contain the following properties
+## flowExecutionUrl - the form action location
+## flowRequestContext - the Spring Web Flow RequestContext
+## flowExecutionKey - the SWF execution key (this is built into the flowExecutionUrl)
+## profileRequestContext - root of context tree
+## authenticationContext - context with authentication request information
+## authenticationErrorContext - context with login error state
+## authenticationWarningContext - context with login warning state
+## rpUIContext - the context with SP UI information from the metadata
+## encoder - HTMLEncoder class
+## request - HttpServletRequest
+## response - HttpServletResponse
+## environment - Spring Environment object for property resolution
+## custom - arbitrary object injected by deployer
+##
+#set ($rpContext = $profileRequestContext.getSubcontext('net.shibboleth.idp.profile.context.RelyingPartyContext'))
+##
+<!DOCTYPE html>
+<html>
+    <head>
+        <meta charset="utf-8">
+        <meta name="viewport" content="width=device-width,initial-scale=1.0">
+        <title>#springMessageText("idp.title", "Web Login Service")</title>
+        <link rel="stylesheet" type="text/css" href="$request.getContextPath()/css/main.css">
+    </head>
+    <body>
+    <div class="wrapper">
+      <div class="container">
+        <header>
+          <img src="$request.getContextPath()#springMessage("idp.logo")" alt="#springMessageText("idp.logo.alt-text", "logo")">
+        </header>
+
+        <div class="content">
+          <div class="column one">
+            #parse("totp-error.vm")
+
+            <form action="$flowExecutionUrl" method="post">
+                #parse("csrf/csrf.vm")
+                #set ($serviceName = $rpUIContext.serviceName)
+                #if ($serviceName && !$rpContext.getRelyingPartyId().contains($serviceName))
+                  <legend>
+                    #springMessageText("idp.login.loginTo", "Login to") $encoder.encodeForHTML($serviceName)
+                  </legend>
+                #end
+                            
+                <div class="form-element-wrapper">
+                  <label for="tokencode">#springMessageText("idp.totp.field", "Foo")</label>
+                  <input class="form-element form-field" id="tokencode" name="tokencode" type="text" value="" />
+                </div>
+    
+    
+                <div class="form-element-wrapper">
+                  <button class="form-element form-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>
+                </div>
+            </form>
+
+            #*
+              //
+              //    SP Description & Logo (optional)
+              //    These idpui lines will display added information (if available
+              //    in the metadata) about the Service Provider (SP) that requested
+              //    authentication. These idpui lines are "active" in this example
+              //    (not commented out) - this extra SP info will be displayed.
+              //    Remove or comment out these lines to stop the display of the
+              //    added SP information.
+              //
+            *#
+            #set ($logo = $rpUIContext.getLogo())
+            #if ($logo)
+              <img src= "$encoder.encodeForHTMLAttribute($logo)"
+                  alt="$encoder.encodeForHTMLAttribute($serviceName)">
+            #end
+            #set ($desc = $rpUIContext.getServiceDescription())
+            #if ($desc)
+              $encoder.encodeForHTML($desc)
+            #end
+            
+          </div>
+          <div class="column two">
+            <ul class="list list-help">
+              #if ($passwordEnabled)
+                <li class="list-help-item"><a href="#springMessageText("idp.url.password.reset", '#')"><span class="item-marker">›</span> #springMessageText("idp.login.forgotPassword", "Forgot your password?")</a></li>
+              #end
+              <li class="list-help-item"><a href="#springMessageText("idp.url.helpdesk", '#')"><span class="item-marker">›</span> #springMessageText("idp.login.needHelp", "Need Help?")</a></li>
+            </ul>
+          </div>
+        </div>
+      </div>
+
+      <footer>
+        <div class="container container-footer">
+          <p class="footer-text">#springMessageText("idp.footer", "Insert your footer text here.")</p>
+        </div>
+      </footer>
+    </div>
+    
+     </body>
+</html>
\ No newline at end of file
diff --git a/totp-impl/src/test/java/net/shibboleth/idp/plugin/totp/impl/ExtractTOTPFromFormRequestTest.java b/totp-impl/src/test/java/net/shibboleth/idp/plugin/totp/impl/ExtractTOTPFromFormRequestTest.java
index 2b0d2e0..ad78bbe 100644
--- a/totp-impl/src/test/java/net/shibboleth/idp/plugin/totp/impl/ExtractTOTPFromFormRequestTest.java
+++ b/totp-impl/src/test/java/net/shibboleth/idp/plugin/totp/impl/ExtractTOTPFromFormRequestTest.java
@@ -48,6 +48,7 @@ public class ExtractTOTPFromFormRequestTest extends BaseAuthenticationContextTes
     
     @Test public void testNoServlet() throws Exception {
         action = new ExtractTOTPFromFormRequest();
+        action.setUsernameLookupStrategy(FunctionSupport.constant("jdoe"));
         action.initialize();
         final Event event = action.execute(src);
         
@@ -60,7 +61,7 @@ public class ExtractTOTPFromFormRequestTest extends BaseAuthenticationContextTes
         action.initialize();
         final Event event = action.execute(src);
         
-        ActionTestingSupport.assertEvent(event, AuthnEventIds.NO_CREDENTIALS);
+        ActionTestingSupport.assertEvent(event, AuthnEventIds.UNKNOWN_USERNAME);
     }
 
     @Test public void testMissingField() throws Exception {
@@ -79,7 +80,7 @@ public class ExtractTOTPFromFormRequestTest extends BaseAuthenticationContextTes
         ((MockHttpServletRequest) action.getHttpServletRequest()).addParameter("Foo", "A123456");
         
         final Event event = action.execute(src);
-        ActionTestingSupport.assertEvent(event, AuthnEventIds.NO_CREDENTIALS);
+        ActionTestingSupport.assertEvent(event, AuthnEventIds.INVALID_CREDENTIALS);
     }
 
     @Test public void testValid() throws Exception {
diff --git a/totp-impl/src/test/java/net/shibboleth/idp/plugin/totp/impl/ExtractTOTPFromHeaderTest.java b/totp-impl/src/test/java/net/shibboleth/idp/plugin/totp/impl/ExtractTOTPFromHeaderTest.java
index b8b3ad9..3ef4184 100644
--- a/totp-impl/src/test/java/net/shibboleth/idp/plugin/totp/impl/ExtractTOTPFromHeaderTest.java
+++ b/totp-impl/src/test/java/net/shibboleth/idp/plugin/totp/impl/ExtractTOTPFromHeaderTest.java
@@ -48,6 +48,7 @@ public class ExtractTOTPFromHeaderTest extends BaseAuthenticationContextTest {
     
     @Test public void testNoServlet() throws Exception {
         action = new ExtractTOTPFromHeader();
+        action.setUsernameLookupStrategy(FunctionSupport.constant("jdoe"));
         action.initialize();
         final Event event = action.execute(src);
         
@@ -60,7 +61,7 @@ public class ExtractTOTPFromHeaderTest extends BaseAuthenticationContextTest {
         action.initialize();
         final Event event = action.execute(src);
         
-        ActionTestingSupport.assertEvent(event, AuthnEventIds.NO_CREDENTIALS);
+        ActionTestingSupport.assertEvent(event, AuthnEventIds.UNKNOWN_USERNAME);
     }
 
     @Test public void testMissingHeader() throws Exception {
@@ -79,7 +80,7 @@ public class ExtractTOTPFromHeaderTest extends BaseAuthenticationContextTest {
         ((MockHttpServletRequest) action.getHttpServletRequest()).addHeader("X-Foo", "A123456");
         
         final Event event = action.execute(src);
-        ActionTestingSupport.assertEvent(event, AuthnEventIds.NO_CREDENTIALS);
+        ActionTestingSupport.assertEvent(event, AuthnEventIds.INVALID_CREDENTIALS);
     }
 
     @Test public void testValid() throws Exception {
diff --git a/totp-impl/src/test/java/net/shibboleth/idp/plugin/totp/impl/GoogleAuthenticatorCredentialValidatorTest.java b/totp-impl/src/test/java/net/shibboleth/idp/plugin/totp/impl/GoogleAuthenticatorCredentialValidatorTest.java
index 7dd69de..16c8d41 100644
--- a/totp-impl/src/test/java/net/shibboleth/idp/plugin/totp/impl/GoogleAuthenticatorCredentialValidatorTest.java
+++ b/totp-impl/src/test/java/net/shibboleth/idp/plugin/totp/impl/GoogleAuthenticatorCredentialValidatorTest.java
@@ -88,7 +88,7 @@ public class GoogleAuthenticatorCredentialValidatorTest extends BaseAuthenticati
         action.initialize();
 
         final Event event = action.execute(src);
-        ActionTestingSupport.assertEvent(event, AuthnEventIds.NO_CREDENTIALS);
+        ActionTestingSupport.assertEvent(event, AuthnEventIds.UNKNOWN_USERNAME);
     }
 
 
@@ -101,7 +101,7 @@ public class GoogleAuthenticatorCredentialValidatorTest extends BaseAuthenticati
         action.initialize();
 
         final Event event = action.execute(src);
-        ActionTestingSupport.assertEvent(event, AuthnEventIds.INVALID_CREDENTIALS);
+        ActionTestingSupport.assertEvent(event, AuthnEventIds.NO_CREDENTIALS);
     }
 
     @Test public void testMissingSeeds() throws Exception {

-- 
To stop receiving notification emails like this one, please contact
the administrator of this repository.


More information about the commits mailing list