[java-plugin-shibd] branch main updated: Add inline secrets to Agents, wire in authentication beans.

Scott Cantor cantor.2 at osu.edu
Thu May 23 16:33:31 UTC 2024


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

scantor pushed a commit to branch main
in repository java-plugin-shibd.

View the commit online:
http://git.shibboleth.net/view/?p=java-plugin-shibd.git;a=commit;h=6aade001a2a7a6092235c6b2504b961bde360a8b

The following commit(s) were added to refs/heads/main by this push:
     new 6aade00  Add inline secrets to Agents, wire in authentication beans.
6aade00 is described below

commit 6aade001a2a7a6092235c6b2504b961bde360a8b
Author: Scott Cantor <cantor.2 at osu.edu>
AuthorDate: Thu May 23 12:33:28 2024 -0400

    Add inline secrets to Agents, wire in authentication beans.
---
 .../idp/flows/sp/abstract/sp-abstract-beans.xml    | 106 +++++++++++++++++-
 .../shibboleth/idp/module/conf/sp/sp.properties    |   6 +-
 .../net/shibboleth/sp/conf/agents-system.xml       |   2 +-
 .../src/main/java/net/shibboleth/sp/Agent.java     |  10 ++
 .../authn/impl/AgentSecretCredentialValidator.java | 117 +++++++++++++++++++
 .../java/net/shibboleth/sp/impl/BasicAgent.java    |  22 +++-
 .../impl/AgentSecretCredentialValidatorTest.java   | 124 +++++++++++++++++++++
 7 files changed, 381 insertions(+), 6 deletions(-)

diff --git a/sp-conf-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/sp/abstract/sp-abstract-beans.xml b/sp-conf-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/sp/abstract/sp-abstract-beans.xml
index 2ebd014..c32e617 100644
--- a/sp-conf-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/sp/abstract/sp-abstract-beans.xml
+++ b/sp-conf-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/sp/abstract/sp-abstract-beans.xml
@@ -42,7 +42,7 @@
     <bean id="ValidateCachedAuthentication"
         class="net.shibboleth.sp.authn.impl.ValidateCachedAuthentication" scope="prototype"
         p:httpServletRequestSupplier-ref="shibboleth.HttpServletRequestSupplier"
-        p:cookieName="%{sp.agent.cachedAuthentication.cookie:__Host-shibsp_agent_token}"
+        p:cookieName="%{sp.agent.authn.cached.cookieName:__Host-shibsp_agent_token}"
         p:cookieManager-ref="sp.CookieManager"
         p:dataSealer-ref="shibboleth.DataSealer" />
 
@@ -51,6 +51,108 @@
         p:httpOnly="true"
         p:cookieDomain=""
         p:cookiePath="/"
-        p:maxAge="%{sp.agent.cachedAuthentication.maxAge:3600}" />
+        p:maxAge="%{sp.agent.authn.cached.maxAge:3600}" />
+
+    <bean id="ValidateCredentials"
+        class="net.shibboleth.idp.authn.impl.ValidateCredentials" scope="prototype"
+        p:requireAll="%{sp.agent.authn.requireAll:false}"
+        p:validators="#{getObject('shibboleth.AgentValidators') ?: getObject('DefaultAgentValidators')}"
+        p:cleanupHook-ref="DefaultCleanupHook" />
+
+    <bean id="DefaultCleanupHook"
+        class="net.shibboleth.idp.authn.impl.ValidateCredentials.UsernamePasswordCleanupHook" />
+
+    <!-- ======== Beans for agent authentication ======== -->
+
+    <util:list id="DefaultAgentValidators">
+        <ref bean="shibboleth.AgentSecretValidator" />
+    </util:list>
+        
+    <!-- Validator parent beans -->
+
+    <bean id="shibboleth.CredentialValidator" abstract="true"
+        p:savePasswordToCredentialSet="%{sp.agent.authn.retainAsPrivateCredential:false}" />
+    
+    <bean id="shibboleth.AgentSecretValidator" parent="shibboleth.CredentialValidator"
+        class="net.shibboleth.sp.authn.impl.AgentSecretCredentialValidator"
+        p:id="spagent-internal" />
+    
+    <bean id="shibboleth.JAASValidator" parent="shibboleth.CredentialValidator"
+        class="net.shibboleth.idp.authn.impl.JAASCredentialValidator" abstract="true"
+        p:id="spagent-jaas" />
+
+    <bean id="shibboleth.KerberosValidator" parent="shibboleth.CredentialValidator"
+        class="net.shibboleth.idp.authn.impl.KerberosCredentialValidator" abstract="true"
+        p:id="spagent-krb5" />
+
+    <bean id="shibboleth.LDAPValidator" parent="shibboleth.CredentialValidator" lazy-init="true"
+        class="net.shibboleth.idp.authn.impl.LDAPCredentialValidator"
+        p:id="spagent-ldap"
+        p:authenticator-ref="shibboleth.authn.LDAP.authenticator" />
+
+    <bean id="shibboleth.HTPasswdValidator" abstract="true"
+        class="net.shibboleth.idp.authn.impl.HTPasswdCredentialValidator"
+        p:id="spagent-htpasswd" />
+
+    <bean id="shibboleth.X509Validator" abstract="true"
+        class="net.shibboleth.idp.authn.impl.X509CertificateCredentialValidator"
+        p:id="spagent-x509" />
+
+    <!-- Parent beans for custom ldaptive types. -->
+    
+    <bean id="shibboleth.authn.LDAP.authenticator" parent="shibboleth.LDAPAuthenticationFactory"
+        lazy-init="true" />
+
+    <bean id="shibboleth.X509ResourceCredentialConfig"
+        class="net.shibboleth.idp.authn.impl.X509ResourceCredentialConfig" abstract="true" /> 
+    <bean id="shibboleth.KeystoreResourceCredentialConfig"
+        class="net.shibboleth.idp.authn.impl.KeystoreResourceCredentialConfig" abstract="true" /> 
+    
+    <bean id="shibboleth.authn.LDAP.trustCertificates" parent="shibboleth.X509ResourceCredentialConfig"
+        p:trustCertificates="%{sp.agent.authn.LDAP.trustCertificates:undefined}" />
+    <bean id="shibboleth.authn.LDAP.truststore" parent="shibboleth.KeystoreResourceCredentialConfig"
+        p:truststore="%{sp.agent.authn.LDAP.trustStore:undefined}" />
+
+    <bean id="shibboleth.LDAPAuthenticationFactory" abstract="true"
+        class="net.shibboleth.idp.authn.config.LDAPAuthenticationFactoryBean"
+        p:authenticatorType="#{'%{sp.agent.authn.LDAP.authenticator:anonSearchAuthenticator}'.trim()}"
+        p:trustType="#{'%{sp.agent.authn.LDAP.sslConfig:certificateTrust}'.trim()}"
+        p:connectionStrategyType="#{'%{sp.agent.authn.LDAP.connectionStrategy:ACTIVE_PASSIVE}'.trim()}"
+        p:ldapUrl="%{sp.agent.authn.LDAP.ldapURL:ldap://localhost:10389}"
+        p:useStartTLS="%{sp.agent.authn.LDAP.useStartTLS:true}"
+        p:connectTimeout="%{sp.agent.authn.LDAP.connectTimeout:PT3S}"
+        p:responseTimeout="%{sp.agent.authn.LDAP.responseTimeout:PT3S}"
+        p:trustCertificatesCredentialConfig-ref="shibboleth.authn.OAuth2Client.LDAP.trustCertificates"
+        p:truststoreCredentialConfig-ref="shibboleth.authn.OAuth2Client.LDAP.truststore"
+        p:disablePooling="%{sp.agent.authn.LDAP.disablePooling:false}"
+        p:blockWaitTime="%{sp.agent.authn.pool.LDAP.blockWaitTime:PT3S}"
+        p:minPoolSize="%{sp.agent.authn..pool.LDAP.minSize:3}"
+        p:maxPoolSize="%{sp.agent.authn..pool.LDAP.maxSize:10}"
+        p:validateOnCheckout="%{sp.agent.authn..pool.LDAP.validateOnCheckout:false}"
+        p:validatePeriodically="%{sp.agent.authn..pool.LDAP.validatePeriodically:true}"
+        p:validatePeriod="%{sp.agent.authn..pool.LDAP.validatePeriod:PT5M}"
+        p:validateDn="#{'%{sp.agent.authn..pool.LDAP.validateDN:}'.trim()}"
+        p:validateFilter="#{'%{sp.agent.authn..pool.LDAP.validateFilter:(objectClass=*)}'.trim()}"
+        p:bindPoolPassivatorType="#{'%{sp.agent.authn.LDAP.bindPoolPassivator:none}'.trim()}"
+        p:prunePeriod="%{sp.agent.authn..pool.LDAP.prunePeriod:PT5M}"
+        p:idleTime="%{sp.agent.authn..pool.LDAP.idleTime:PT10M}"
+        p:dnFormat="%{sp.agent.authn.LDAP.dnFormat:undefined}"
+        p:baseDn="#{'%{sp.agent.authn.LDAP.baseDN:undefined}'.trim()}"
+        p:userFilter="#{'%{sp.agent.authn.LDAP.userFilter:undefined}'.trim()}"
+        p:subtreeSearch="%{sp.agent.authn.LDAP.subtreeSearch:false}"
+        p:resolveEntryOnFailure="%{sp.agent.authn.LDAP.resolveEntryOnFailure:false}"
+        p:resolveEntryWithBindDn="%{sp.agent.authn.LDAP.resolveEntryWithBindDN:false}"
+        p:velocityEngine-ref="shibboleth.VelocityEngine"
+        p:bindDn="#{'%{sp.agent.authn.LDAP.bindDN:undefined}'.trim()}"
+        p:bindDnCredential="%{sp.agent.authn.LDAP.bindDNCredential:undefined}"
+        p:usePasswordPolicy="%{sp.agent.authn.LDAP.usePasswordPolicy:false}"
+        p:usePasswordExpiration="%{sp.agent.authn.LDAP.usePasswordExpiration:false}"
+        p:activeDirectory="%{sp.agent.authn.LDAP.activeDirectory:false}"
+        p:freeIPA="%{sp.agent.authn.LDAP.freeIPADirectory:false}"
+        p:EDirectory="%{sp.agent.authn.LDAP.eDirectory:false}"
+        p:accountStateExpirationPeriod="%{sp.agent.authn.LDAP.accountStateExpirationPeriod:#{null}}"
+        p:accountStateWarningPeriod="%{sp.agent.authn.LDAP.accountStateWarningPeriod:#{null}}"
+        p:accountStateLoginFailures="%{sp.agent.authn.LDAP.accountStateLoginFailures:0}" />
+
 
 </beans>
diff --git a/sp-conf-impl/src/main/resources/net/shibboleth/idp/module/conf/sp/sp.properties b/sp-conf-impl/src/main/resources/net/shibboleth/idp/module/conf/sp/sp.properties
index 4581ed4..20efc04 100644
--- a/sp-conf-impl/src/main/resources/net/shibboleth/idp/module/conf/sp/sp.properties
+++ b/sp-conf-impl/src/main/resources/net/shibboleth/idp/module/conf/sp/sp.properties
@@ -22,6 +22,8 @@ sp.encryption.cert = %{idp.home}/credentials/sp/sp-encryption.crt
 #sp.encryption.cert.2 = %{idp.home}/credentials/sp/sp-encryption-old.crt
 
 # Set to Basic to require shared secret authentication
-#sp.agent.authentication = None
+#sp.agent.authn.method = None
 # Set false to globally disable cookie-based authentication by agents
-#sp.agent.cachedAuhentication = true
\ No newline at end of file
+#sp.agent.authn.cached = true
+#sp.agent.authn.cached.cookieName = __Host-shibsp_agent_token
+#sp.agent.authn.cached.maxAge = 3600
diff --git a/sp-conf-impl/src/main/resources/net/shibboleth/sp/conf/agents-system.xml b/sp-conf-impl/src/main/resources/net/shibboleth/sp/conf/agents-system.xml
index a4ac0e1..35314b8 100644
--- a/sp-conf-impl/src/main/resources/net/shibboleth/sp/conf/agents-system.xml
+++ b/sp-conf-impl/src/main/resources/net/shibboleth/sp/conf/agents-system.xml
@@ -22,7 +22,7 @@
 
     <bean id="shibboleth.Agent" class="net.shibboleth.sp.impl.BasicAgent" abstract="true"
         p:allowedAddressRanges="#{{ '127.0.0.1/32', '::1/128' }}"
-        p:supportsCachedAuthentication="%{sp.agent.cachedAuhentication:true}" />
+        p:supportsCachedAuthentication="%{sp.agent.authn.cached:true}" />
 
     <bean id="shibboleth.Application" class="net.shibboleth.sp.impl.BasicApplication" abstract="true"
         p:metadataResolver-ref="shibboleth.MetadataResolverService"
diff --git a/sp-server-api/src/main/java/net/shibboleth/sp/Agent.java b/sp-server-api/src/main/java/net/shibboleth/sp/Agent.java
index 981e94d..d9f71ff 100644
--- a/sp-server-api/src/main/java/net/shibboleth/sp/Agent.java
+++ b/sp-server-api/src/main/java/net/shibboleth/sp/Agent.java
@@ -46,6 +46,16 @@ public interface Agent extends IdentifiedComponent {
      * @return set of address ranges
      */
     @Nonnull Set<IPRange> getAllowedAddressRanges();
+
+    /**
+     * Get the shared secrets configured directly on this agent.
+     * 
+     * <p>While it is expected that most secret-based agent authentication will rely on
+     * an external service (e.g., LDAP), direct conifguration can be supported.</p>
+     * 
+     * @return set of shared secrets
+     */
+    @Nonnull Set<String> getSharedSecrets();
     
     /**
      * Returns true iff the supplied address matches one of the allowed ranges.
diff --git a/sp-server-impl/src/main/java/net/shibboleth/sp/authn/impl/AgentSecretCredentialValidator.java b/sp-server-impl/src/main/java/net/shibboleth/sp/authn/impl/AgentSecretCredentialValidator.java
new file mode 100644
index 0000000..8a6f9bb
--- /dev/null
+++ b/sp-server-impl/src/main/java/net/shibboleth/sp/authn/impl/AgentSecretCredentialValidator.java
@@ -0,0 +1,117 @@
+/*
+ * Licensed 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.sp.authn.impl;
+
+import java.util.function.Function;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import javax.security.auth.Subject;
+import javax.security.auth.login.LoginException;
+
+import org.opensaml.messaging.context.navigate.ChildContextLookup;
+import org.opensaml.profile.action.EventIds;
+import org.opensaml.profile.context.ProfileRequestContext;
+import org.slf4j.Logger;
+
+import net.shibboleth.idp.authn.AbstractUsernamePasswordCredentialValidator;
+import net.shibboleth.idp.authn.AuthnEventIds;
+import net.shibboleth.idp.authn.CredentialValidator;
+import net.shibboleth.idp.authn.context.AuthenticationContext;
+import net.shibboleth.idp.authn.context.UsernamePasswordContext;
+import net.shibboleth.shared.annotation.constraint.NonnullBeforeExec;
+import net.shibboleth.shared.logic.Constraint;
+import net.shibboleth.shared.primitive.LoggerFactory;
+import net.shibboleth.sp.Agent;
+import net.shibboleth.sp.context.AgentRequestContext;
+
+/**
+ * Simple {@link CredentialValidator} implementation that relies on the shared secrets configured
+ * directly against {@link Agent} instances.
+ */
+public class AgentSecretCredentialValidator extends AbstractUsernamePasswordCredentialValidator {
+
+    /** Class logger. */
+    @Nonnull private final Logger log = LoggerFactory.getLogger(AgentSecretCredentialValidator.class);
+    
+    /** Lookup strategy for {@link AgentRequestContext}. */
+    @Nonnull private Function<ProfileRequestContext,AgentRequestContext> agentRequestContextLookupStrategy;
+    
+    /** Cached agent from context. */
+    @NonnullBeforeExec private Agent agent;
+
+    /** Constructor. */
+    public AgentSecretCredentialValidator() {
+        agentRequestContextLookupStrategy = new ChildContextLookup<>(AgentRequestContext.class);
+    }
+    
+    /**
+     * Sets the lookup strategy for the {@link AgentRequestContext}.
+     * 
+     * @param strategy lookup strategy
+     */
+    public void setAgentRequestContextLookupStrategy(
+            @Nonnull final Function<ProfileRequestContext,AgentRequestContext> strategy) {
+        checkSetterPreconditions();
+        
+        agentRequestContextLookupStrategy = Constraint.isNotNull(strategy,
+                "AgentRequestContext lookup strategy cannot be null");
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    @Nullable protected Subject doValidate(@Nonnull final ProfileRequestContext profileRequestContext,
+            @Nonnull final AuthenticationContext authenticationContext,
+            @Nonnull final UsernamePasswordContext usernamePasswordContext,
+            @Nullable final WarningHandler warningHandler, @Nullable final ErrorHandler errorHandler)
+                    throws Exception {
+        
+        final AgentRequestContext agentContext = agentRequestContextLookupStrategy.apply(profileRequestContext);
+        final Agent agent = agentContext != null ? agentContext.getAgent() : null;
+        if (agent == null) {
+            log.error("{} Agent missing from request context", getLogPrefix());
+            final LoginException e = new LoginException(EventIds.INVALID_PROFILE_CTX); 
+            if (errorHandler != null) { 
+                errorHandler.handleError(profileRequestContext, authenticationContext, e,
+                        EventIds.INVALID_PROFILE_CTX);
+            }
+            throw e;
+        }
+
+        if (agent.getSharedSecrets().isEmpty()) {
+            log.debug("{} No shared secrets configured for agent '{}', ignoring", getLogPrefix(), agent.getId());
+            return null;
+        }
+        
+        log.debug("{} Attempting to authenticate agent '{}' ", getLogPrefix(), agent.getId());
+        
+        for (final String candidate : agent.getSharedSecrets()) {
+            if (candidate.equals(usernamePasswordContext.getPassword())) {
+                log.info("{} Authentication of agent '{}' succeeded", getLogPrefix(), agent.getId());
+                return populateSubject(new Subject(), usernamePasswordContext);
+            }
+        }
+        
+        log.info("{} Authentication of agent '{}' failed", getLogPrefix(), agent.getId());
+        
+        final LoginException e = new LoginException(AuthnEventIds.INVALID_CREDENTIALS); 
+        if (errorHandler != null) { 
+            errorHandler.handleError(profileRequestContext, authenticationContext, e,
+                    AuthnEventIds.INVALID_CREDENTIALS);
+        }
+        throw e;
+    }
+
+}
\ No newline at end of file
diff --git a/sp-server-impl/src/main/java/net/shibboleth/sp/impl/BasicAgent.java b/sp-server-impl/src/main/java/net/shibboleth/sp/impl/BasicAgent.java
index 191ad54..fc72d5f 100644
--- a/sp-server-impl/src/main/java/net/shibboleth/sp/impl/BasicAgent.java
+++ b/sp-server-impl/src/main/java/net/shibboleth/sp/impl/BasicAgent.java
@@ -51,6 +51,9 @@ public class BasicAgent extends DefaultRelyingPartyConfigurationResolver impleme
     /** Allowed address ranges. */
     @Nonnull private Set<IPRange> allowedAddressRanges;
     
+    /** Internally configured shared secrets. */
+    @Nonnull private Set<String> sharedSecrets;
+    
     /** Application map. */
     @Nonnull private Map<String,Application> applicationMap;
     
@@ -61,6 +64,7 @@ public class BasicAgent extends DefaultRelyingPartyConfigurationResolver impleme
     public BasicAgent() {
         supportsCachedAuthentication = true;
         allowedAddressRanges = CollectionSupport.emptySet();
+        sharedSecrets = CollectionSupport.emptySet();
         applicationMap = CollectionSupport.emptyMap();
         issuerLookupStrategy = FunctionSupport.constant(null);
     }
@@ -80,13 +84,29 @@ public class BasicAgent extends DefaultRelyingPartyConfigurationResolver impleme
         
         allowedAddressRanges = ranges != null ? CollectionSupport.copyToSet(ranges) : CollectionSupport.emptySet();
     }
-
+    
     /** {@inheritDoc} */
     public boolean isAllowed(@Nonnull final InetAddress address) {
         checkComponentActive();
         
         return allowedAddressRanges.stream().anyMatch(r -> r.contains(address));
     }
+    
+    /** {@inheritDoc} */
+    @Nonnull public Set<String> getSharedSecrets() {
+        return sharedSecrets;
+    }
+    
+    /**
+     * Sets the shared secrets to store directly in this agent.
+     * 
+     * @param secrets shared secrets for agent authentication
+     */
+    public void setSharedSecrets(@Nullable final Set<String> secrets) {
+        checkSetterPreconditions();
+        
+        sharedSecrets = secrets != null ? CollectionSupport.copyToSet(secrets) : CollectionSupport.emptySet();
+    }
 
     /** {@inheritDoc} */
     public boolean isSupportsCachedAuthentication() {
diff --git a/sp-server-impl/src/test/java/net/shibboleth/sp/authn/impl/AgentSecretCredentialValidatorTest.java b/sp-server-impl/src/test/java/net/shibboleth/sp/authn/impl/AgentSecretCredentialValidatorTest.java
new file mode 100644
index 0000000..94b95d9
--- /dev/null
+++ b/sp-server-impl/src/test/java/net/shibboleth/sp/authn/impl/AgentSecretCredentialValidatorTest.java
@@ -0,0 +1,124 @@
+/*
+ * Licensed 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.sp.authn.impl;
+
+import java.util.Set;
+
+import javax.security.auth.Subject;
+import javax.security.auth.login.LoginException;
+
+import org.opensaml.profile.context.ProfileRequestContext;
+import org.opensaml.profile.testing.RequestContextBuilder;
+import org.springframework.mock.web.MockHttpServletRequest;
+import org.testng.Assert;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import net.shibboleth.idp.authn.context.AuthenticationContext;
+import net.shibboleth.idp.authn.context.UsernamePasswordContext;
+import net.shibboleth.idp.authn.principal.UsernamePrincipal;
+import net.shibboleth.shared.collection.CollectionSupport;
+import net.shibboleth.shared.component.ComponentInitializationException;
+import net.shibboleth.sp.context.AgentRequestContext;
+import net.shibboleth.sp.impl.BasicAgent;
+
+/**
+ * Unit test for {@link AgentSecretCredentialValidator}.
+ */
+ at SuppressWarnings("javadoc")
+public class AgentSecretCredentialValidatorTest {
+
+    private ProfileRequestContext prc;
+    private AuthenticationContext ac;
+    private UsernamePasswordContext upc;
+    private MockHttpServletRequest request;
+    
+    private BasicAgent agent;
+    private AgentSecretCredentialValidator validator;
+    
+    @BeforeMethod
+    public void setUp() throws ComponentInitializationException {
+        prc = new RequestContextBuilder().buildProfileRequestContext();
+        ac = prc.ensureSubcontext(AuthenticationContext.class);
+        upc = ac.ensureSubcontext(UsernamePasswordContext.class);
+        upc.setUsername("foo");
+        
+        agent = new BasicAgent();
+        agent.setId("foo");
+        agent.setSharedSecrets(CollectionSupport.setOf("zork", "enchanter"));
+        agent.initialize();
+        
+        validator = new AgentSecretCredentialValidator();
+        validator.setId("test");
+        validator.initialize();
+    }
+
+    @Test
+    public void testNoAgent() {
+        try {
+            validator.validate(prc, ac, null, null);
+            Assert.fail("Validator should have thrown");
+        } catch (final Exception e) {
+            Assert.assertTrue(e instanceof LoginException);
+        }
+    }
+
+    @Test
+    public void testSuccess() {
+        prc.ensureSubcontext(AgentRequestContext.class).setAgent(agent);
+        upc.setPassword("enchanter");
+        
+        try {
+            final Subject subject = validator.validate(prc, ac, null, null);
+            assert subject != null;
+            final Set<UsernamePrincipal> principals = subject.getPrincipals(UsernamePrincipal.class);
+            Assert.assertTrue(principals.contains(new UsernamePrincipal(agent.getId())));
+        } catch (final Exception e) {
+            Assert.fail("Validator should not have thrown");
+        }
+    }
+
+    @Test
+    public void testFailure() {
+        prc.ensureSubcontext(AgentRequestContext.class).setAgent(agent);
+        upc.setPassword("foo");
+        
+        try {
+            validator.validate(prc, ac, null, null);
+            Assert.fail("Validator should have thrown");
+        } catch (final Exception e) {
+            Assert.assertTrue(e instanceof LoginException);
+        }
+    }
+
+    @Test
+    public void testIgnored() throws ComponentInitializationException {
+
+        agent = new BasicAgent();
+        agent.setId("foo");
+        agent.initialize();
+
+        prc.ensureSubcontext(AgentRequestContext.class).setAgent(agent);
+        upc.setPassword("enchanter");
+
+        try {
+            final Subject subject = validator.validate(prc, ac, null, null);
+            Assert.assertNull(subject);
+        } catch (final Exception e) {
+            Assert.fail("Validator should not have thrown");
+        }
+    }
+
+}
\ 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