diff --git a/server/src/main/java/org/cloudfoundry/identity/uaa/audit/AuditEventType.java b/server/src/main/java/org/cloudfoundry/identity/uaa/audit/AuditEventType.java
index e38c5ce256f..f2d6db171a2 100644
--- a/server/src/main/java/org/cloudfoundry/identity/uaa/audit/AuditEventType.java
+++ b/server/src/main/java/org/cloudfoundry/identity/uaa/audit/AuditEventType.java
@@ -58,7 +58,7 @@ public enum AuditEventType {
ServiceProviderModifiedEvent(34),
UserAccountUnlockedEvent(35),
TokenRevocationEvent(36),
- PasswordAuthenticationSuccess(37),
+ IdentityProviderAuthenticationSuccess(37),
PasswordAuthenticationFailure(38),
MfaAuthenticationSuccess(39);
diff --git a/server/src/main/java/org/cloudfoundry/identity/uaa/authentication/event/AbstractUaaAuthenticationEvent.java b/server/src/main/java/org/cloudfoundry/identity/uaa/authentication/event/AbstractUaaAuthenticationEvent.java
index c2b810c033f..e98cdb21ea2 100644
--- a/server/src/main/java/org/cloudfoundry/identity/uaa/authentication/event/AbstractUaaAuthenticationEvent.java
+++ b/server/src/main/java/org/cloudfoundry/identity/uaa/authentication/event/AbstractUaaAuthenticationEvent.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Cloud Foundry
+ * Cloud Foundry
* Copyright (c) [2009-2016] Pivotal Software, Inc. All Rights Reserved.
*
* This product is licensed to you under the Apache License, Version 2.0 (the "License").
@@ -19,7 +19,7 @@
/**
* @author Luke Taylor
*/
-abstract class AbstractUaaAuthenticationEvent extends AbstractUaaEvent {
+public abstract class AbstractUaaAuthenticationEvent extends AbstractUaaEvent {
AbstractUaaAuthenticationEvent(Authentication authentication) {
super(authentication);
diff --git a/server/src/main/java/org/cloudfoundry/identity/uaa/authentication/event/IdentityProviderAuthenticationSuccessEvent.java b/server/src/main/java/org/cloudfoundry/identity/uaa/authentication/event/IdentityProviderAuthenticationSuccessEvent.java
new file mode 100644
index 00000000000..4ec2497a66e
--- /dev/null
+++ b/server/src/main/java/org/cloudfoundry/identity/uaa/authentication/event/IdentityProviderAuthenticationSuccessEvent.java
@@ -0,0 +1,40 @@
+/*
+ * Cloud Foundry
+ * Copyright (c) [2009-2018] Pivotal Software, Inc. All Rights Reserved.
+ *
, ApplicationEventPublisherAware {
+
+ private final ScimUserProvisioning scimUserProvisioning;
+ private final MfaChecker checker;
+ private ApplicationEventPublisher publisher;
+
+ public AuthenticationSuccessListener(ScimUserProvisioning scimUserProvisioning,
+ MfaChecker checker) {
+ this.scimUserProvisioning = scimUserProvisioning;
+ this.checker = checker;
+ }
+
+ @Override
+ public void onApplicationEvent(AbstractUaaAuthenticationEvent event) {
+ if (event instanceof UserAuthenticationSuccessEvent) {
+ onApplicationEvent((UserAuthenticationSuccessEvent) event);
+ } else if (event instanceof IdentityProviderAuthenticationSuccessEvent) {
+ IdentityProviderAuthenticationSuccessEvent passwordAuthEvent = (IdentityProviderAuthenticationSuccessEvent) event;
+ UserAuthenticationSuccessEvent userEvent = new UserAuthenticationSuccessEvent(
+ passwordAuthEvent.getUser(),
+ (Authentication) passwordAuthEvent.getSource()
+ );
+ if (!checker.isMfaEnabled(userEvent.getIdentityZone(), userEvent.getUser().getOrigin())) {
+ publisher.publishEvent(userEvent);
+ }
+ } else if (event instanceof MfaAuthenticationSuccessEvent) {
+ MfaAuthenticationSuccessEvent mfaEvent = (MfaAuthenticationSuccessEvent) event;
+ UserAuthenticationSuccessEvent userEvent = new UserAuthenticationSuccessEvent(
+ mfaEvent.getUser(),
+ (Authentication) mfaEvent.getSource()
+ );
+ publisher.publishEvent(userEvent);
+ }
+ }
+
+ protected void onApplicationEvent(UserAuthenticationSuccessEvent event) {
+ UaaUser user = event.getUser();
+ if (user.isLegacyVerificationBehavior() && !user.isVerified()) {
+ scimUserProvisioning.verifyUser(user.getId(), -1, IdentityZoneHolder.get().getId());
+ }
+ UaaAuthentication authentication = (UaaAuthentication) event.getAuthentication();
+ authentication.setLastLoginSuccessTime(user.getLastLogonTime());
+ scimUserProvisioning.updateLastLogonTime(user.getId(), IdentityZoneHolder.get().getId());
+ }
+
+
+ @Override
+ public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
+ this.publisher = applicationEventPublisher;
+ }
+
+ public void publish(ApplicationEvent event) {
+ if (publisher != null) {
+ publisher.publishEvent(event);
+ }
+ }
+}
diff --git a/server/src/main/java/org/cloudfoundry/identity/uaa/authentication/listener/UserAuthenticationSuccessListener.java b/server/src/main/java/org/cloudfoundry/identity/uaa/authentication/listener/UserAuthenticationSuccessListener.java
deleted file mode 100644
index 7a77fb9a50f..00000000000
--- a/server/src/main/java/org/cloudfoundry/identity/uaa/authentication/listener/UserAuthenticationSuccessListener.java
+++ /dev/null
@@ -1,40 +0,0 @@
-package org.cloudfoundry.identity.uaa.authentication.listener;
-
-import org.cloudfoundry.identity.uaa.authentication.UaaAuthentication;
-import org.cloudfoundry.identity.uaa.authentication.event.UserAuthenticationSuccessEvent;
-import org.cloudfoundry.identity.uaa.scim.ScimUserProvisioning;
-import org.cloudfoundry.identity.uaa.user.UaaUser;
-import org.cloudfoundry.identity.uaa.zone.IdentityZoneHolder;
-import org.springframework.context.ApplicationListener;
-
-/*******************************************************************************
- * Cloud Foundry
- * Copyright (c) [2009-2015] Pivotal Software, Inc. All Rights Reserved.
- *
- * This product is licensed to you under the Apache License, Version 2.0 (the "License").
- * You may not use this product except in compliance with the License.
- *
- * This product includes a number of subcomponents with
- * separate copyright notices and license terms. Your use of these
- * subcomponents is subject to the terms and conditions of the
- * subcomponent's license, as noted in the LICENSE file.
- *******************************************************************************/
-public class UserAuthenticationSuccessListener implements ApplicationListener {
-
- private final ScimUserProvisioning scimUserProvisioning;
-
- public UserAuthenticationSuccessListener(ScimUserProvisioning scimUserProvisioning) {
- this.scimUserProvisioning = scimUserProvisioning;
- }
-
- @Override
- public void onApplicationEvent(UserAuthenticationSuccessEvent event) {
- UaaUser user = event.getUser();
- if(user.isLegacyVerificationBehavior() && !user.isVerified()) {
- scimUserProvisioning.verifyUser(user.getId(), -1, IdentityZoneHolder.get().getId());
- }
- UaaAuthentication authentication = (UaaAuthentication) event.getAuthentication();
- authentication.setLastLoginSuccessTime(user.getLastLogonTime());
- scimUserProvisioning.updateLastLogonTime(user.getId(), IdentityZoneHolder.get().getId());
- }
-}
diff --git a/server/src/main/java/org/cloudfoundry/identity/uaa/authentication/manager/AuthzAuthenticationManager.java b/server/src/main/java/org/cloudfoundry/identity/uaa/authentication/manager/AuthzAuthenticationManager.java
index 4fc33b409f0..ae76fc5eb0e 100644
--- a/server/src/main/java/org/cloudfoundry/identity/uaa/authentication/manager/AuthzAuthenticationManager.java
+++ b/server/src/main/java/org/cloudfoundry/identity/uaa/authentication/manager/AuthzAuthenticationManager.java
@@ -12,16 +12,20 @@
*******************************************************************************/
package org.cloudfoundry.identity.uaa.authentication.manager;
+import java.util.Calendar;
+import java.util.Collections;
+import java.util.Date;
+import java.util.Locale;
+
import org.cloudfoundry.identity.uaa.authentication.AccountNotVerifiedException;
import org.cloudfoundry.identity.uaa.authentication.AuthenticationPolicyRejectionException;
import org.cloudfoundry.identity.uaa.authentication.UaaAuthentication;
import org.cloudfoundry.identity.uaa.authentication.UaaAuthenticationDetails;
import org.cloudfoundry.identity.uaa.authentication.UaaPrincipal;
+import org.cloudfoundry.identity.uaa.authentication.event.IdentityProviderAuthenticationSuccessEvent;
import org.cloudfoundry.identity.uaa.authentication.event.PasswordAuthenticationFailureEvent;
-import org.cloudfoundry.identity.uaa.authentication.event.PasswordAuthenticationSuccessEvent;
import org.cloudfoundry.identity.uaa.authentication.event.UnverifiedUserAuthenticationEvent;
import org.cloudfoundry.identity.uaa.authentication.event.UserAuthenticationFailureEvent;
-import org.cloudfoundry.identity.uaa.authentication.event.UserAuthenticationSuccessEvent;
import org.cloudfoundry.identity.uaa.authentication.event.UserNotFoundEvent;
import org.cloudfoundry.identity.uaa.constants.OriginKeys;
import org.cloudfoundry.identity.uaa.logging.SanitizedLogFactory;
@@ -32,6 +36,7 @@
import org.cloudfoundry.identity.uaa.user.UaaUserDatabase;
import org.cloudfoundry.identity.uaa.util.ObjectUtils;
import org.cloudfoundry.identity.uaa.zone.IdentityZoneHolder;
+
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
@@ -44,11 +49,6 @@
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.password.PasswordEncoder;
-import java.util.Calendar;
-import java.util.Collections;
-import java.util.Date;
-import java.util.Locale;
-
public class AuthzAuthenticationManager implements AuthenticationManager, ApplicationEventPublisherAware {
private final SanitizedLogFactory.SanitizedLog logger = SanitizedLogFactory.getLog(getClass());
@@ -129,9 +129,7 @@ public Authentication authenticate(Authentication req) throws AuthenticationExce
success.setRequiresPasswordChange(true);
}
- publish(new PasswordAuthenticationSuccessEvent(user, success));
- publish(new UserAuthenticationSuccessEvent(user, success));
-
+ publish(new IdentityProviderAuthenticationSuccessEvent(user, success));
return success;
}
}
diff --git a/server/src/main/java/org/cloudfoundry/identity/uaa/authentication/manager/ExternalLoginAuthenticationManager.java b/server/src/main/java/org/cloudfoundry/identity/uaa/authentication/manager/ExternalLoginAuthenticationManager.java
index 65169177250..686869aa2d2 100644
--- a/server/src/main/java/org/cloudfoundry/identity/uaa/authentication/manager/ExternalLoginAuthenticationManager.java
+++ b/server/src/main/java/org/cloudfoundry/identity/uaa/authentication/manager/ExternalLoginAuthenticationManager.java
@@ -15,14 +15,17 @@
package org.cloudfoundry.identity.uaa.authentication.manager;
-import org.apache.commons.lang.StringUtils;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
+import java.util.Collection;
+import java.util.Date;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+
import org.cloudfoundry.identity.uaa.authentication.AccountNotPreCreatedException;
import org.cloudfoundry.identity.uaa.authentication.UaaAuthentication;
import org.cloudfoundry.identity.uaa.authentication.UaaAuthenticationDetails;
import org.cloudfoundry.identity.uaa.authentication.UaaPrincipal;
-import org.cloudfoundry.identity.uaa.authentication.event.UserAuthenticationSuccessEvent;
+import org.cloudfoundry.identity.uaa.authentication.event.IdentityProviderAuthenticationSuccessEvent;
import org.cloudfoundry.identity.uaa.provider.ExternalIdentityProviderDefinition;
import org.cloudfoundry.identity.uaa.provider.IdentityProvider;
import org.cloudfoundry.identity.uaa.provider.IdentityProviderProvisioning;
@@ -38,6 +41,10 @@
import org.cloudfoundry.identity.uaa.user.UaaUserPrototype;
import org.cloudfoundry.identity.uaa.user.UserInfo;
import org.cloudfoundry.identity.uaa.zone.IdentityZoneHolder;
+
+import org.apache.commons.lang.StringUtils;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationEventPublisher;
@@ -55,12 +62,6 @@
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
-import java.util.Collection;
-import java.util.Date;
-import java.util.HashSet;
-import java.util.LinkedList;
-import java.util.List;
-
import static java.util.Collections.EMPTY_SET;
import static java.util.Optional.ofNullable;
@@ -169,7 +170,7 @@ public Authentication authenticate(Authentication request) throws Authentication
}
UaaAuthentication success = new UaaAuthentication(new UaaPrincipal(user), user.getAuthorities(), uaaAuthenticationDetails);
populateAuthenticationAttributes(success, request, authenticationData);
- publish(new UserAuthenticationSuccessEvent(user, success));
+ publish(new IdentityProviderAuthenticationSuccessEvent(user, success));
return success;
}
diff --git a/server/src/main/java/org/cloudfoundry/identity/uaa/authentication/manager/LoginAuthenticationManager.java b/server/src/main/java/org/cloudfoundry/identity/uaa/authentication/manager/LoginAuthenticationManager.java
index a963b21fbaf..3ac6354ec1d 100644
--- a/server/src/main/java/org/cloudfoundry/identity/uaa/authentication/manager/LoginAuthenticationManager.java
+++ b/server/src/main/java/org/cloudfoundry/identity/uaa/authentication/manager/LoginAuthenticationManager.java
@@ -12,18 +12,22 @@
*******************************************************************************/
package org.cloudfoundry.identity.uaa.authentication.manager;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
+import java.util.Date;
+import java.util.Map;
+
import org.cloudfoundry.identity.uaa.authentication.AuthzAuthenticationRequest;
import org.cloudfoundry.identity.uaa.authentication.UaaAuthentication;
import org.cloudfoundry.identity.uaa.authentication.UaaAuthenticationDetails;
import org.cloudfoundry.identity.uaa.authentication.UaaPrincipal;
-import org.cloudfoundry.identity.uaa.authentication.event.UserAuthenticationSuccessEvent;
+import org.cloudfoundry.identity.uaa.authentication.event.IdentityProviderAuthenticationSuccessEvent;
import org.cloudfoundry.identity.uaa.constants.OriginKeys;
import org.cloudfoundry.identity.uaa.user.UaaAuthority;
import org.cloudfoundry.identity.uaa.user.UaaUser;
import org.cloudfoundry.identity.uaa.user.UaaUserDatabase;
import org.cloudfoundry.identity.uaa.zone.IdentityZoneHolder;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
@@ -37,9 +41,6 @@
import org.springframework.security.oauth2.common.util.RandomValueStringGenerator;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
-import java.util.Date;
-import java.util.Map;
-
public class LoginAuthenticationManager implements AuthenticationManager, ApplicationEventPublisherAware {
public static final String NotANumber = OriginKeys.NotANumber;
@@ -106,9 +107,8 @@ public Authentication authenticate(Authentication request) throws Authentication
throw new BadCredentialsException("Bad Credentials");
}
}
- Authentication success = new UaaAuthentication(new UaaPrincipal(user), user.getAuthorities(),
- authdetails);
- publish(new UserAuthenticationSuccessEvent(user, success));
+ Authentication success = new UaaAuthentication(new UaaPrincipal(user), user.getAuthorities(), authdetails);
+ publish(new IdentityProviderAuthenticationSuccessEvent(user, success));
return success;
}
}
diff --git a/server/src/main/java/org/cloudfoundry/identity/uaa/mfa/MfaChecker.java b/server/src/main/java/org/cloudfoundry/identity/uaa/mfa/MfaChecker.java
new file mode 100644
index 00000000000..2d807b66a3d
--- /dev/null
+++ b/server/src/main/java/org/cloudfoundry/identity/uaa/mfa/MfaChecker.java
@@ -0,0 +1,29 @@
+/*
+ * Cloud Foundry
+ * Copyright (c) [2009-2018] Pivotal Software, Inc. All Rights Reserved.
+ *
+ * This product is licensed to you under the Apache License, Version 2.0 (the "License").
+ * You may not use this product except in compliance with the License.
+ *
+ * This product includes a number of subcomponents with
+ * separate copyright notices and license terms. Your use of these
+ * subcomponents is subject to the terms and conditions of the
+ * subcomponent's license, as noted in the LICENSE file
+ */
+package org.cloudfoundry.identity.uaa.mfa;
+
+import org.cloudfoundry.identity.uaa.provider.IdentityProviderProvisioning;
+import org.cloudfoundry.identity.uaa.zone.IdentityZone;
+
+public class MfaChecker {
+
+ private final IdentityProviderProvisioning providerProvisioning;
+
+ public MfaChecker(IdentityProviderProvisioning providerProvisioning) {
+ this.providerProvisioning = providerProvisioning;
+ }
+
+ public boolean isMfaEnabled(IdentityZone zone, String originKey) {
+ return zone.getConfig().getMfaConfig().isEnabled();
+ }
+}
diff --git a/server/src/main/java/org/cloudfoundry/identity/uaa/mfa/MfaRequiredFilter.java b/server/src/main/java/org/cloudfoundry/identity/uaa/mfa/MfaRequiredFilter.java
index 1135f0c87ab..63722f89178 100644
--- a/server/src/main/java/org/cloudfoundry/identity/uaa/mfa/MfaRequiredFilter.java
+++ b/server/src/main/java/org/cloudfoundry/identity/uaa/mfa/MfaRequiredFilter.java
@@ -44,15 +44,18 @@ public class MfaRequiredFilter extends GenericFilterBean {
private final AntPathRequestMatcher completedMatcher;
private final String redirect;
private final RequestCache cache;
+ private final MfaChecker checker;
public MfaRequiredFilter(String urlFilter,
String redirect,
RequestCache cache,
- String mfaCompleteUrl) {
+ String mfaCompleteUrl,
+ MfaChecker checker) {
inProgressMatcher = new AntPathRequestMatcher(urlFilter);
this.redirect = redirect;
this.cache = cache;
this.completedMatcher = new AntPathRequestMatcher(mfaCompleteUrl);
+ this.checker = checker;
}
@Override
@@ -130,10 +133,11 @@ protected MfaNextStep getNextStep(HttpServletRequest request) {
if (!(a instanceof UaaAuthentication)) {
return MfaNextStep.INVALID_AUTH;
}
- if (!mfaRequired()) {
+ UaaAuthentication uaaAuth = (UaaAuthentication) a;
+ if (!mfaRequired(uaaAuth.getPrincipal().getOrigin())) {
return MfaNextStep.MFA_NOT_REQUIRED;
}
- UaaAuthentication uaaAuth = (UaaAuthentication) a;
+
if (completedMatcher.matches(request) && uaaAuth.getAuthenticationMethods().contains("mfa")) {
return MfaNextStep.MFA_COMPLETED;
}
@@ -158,7 +162,7 @@ protected void sendRedirect(String redirectUrl, HttpServletRequest request, Http
response.sendRedirect(url.toString());
}
- protected boolean mfaRequired() {
- return IdentityZoneHolder.get().getConfig().getMfaConfig().isEnabled();
+ protected boolean mfaRequired(String origin) {
+ return checker.isMfaEnabled(IdentityZoneHolder.get(), origin);
}
}
diff --git a/server/src/main/java/org/cloudfoundry/identity/uaa/provider/saml/LoginSamlAuthenticationProvider.java b/server/src/main/java/org/cloudfoundry/identity/uaa/provider/saml/LoginSamlAuthenticationProvider.java
index 4e8fccc079f..91e86bdb75a 100644
--- a/server/src/main/java/org/cloudfoundry/identity/uaa/provider/saml/LoginSamlAuthenticationProvider.java
+++ b/server/src/main/java/org/cloudfoundry/identity/uaa/provider/saml/LoginSamlAuthenticationProvider.java
@@ -13,12 +13,21 @@
package org.cloudfoundry.identity.uaa.provider.saml;
-import org.apache.commons.lang.StringUtils;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
+import javax.xml.namespace.QName;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Date;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map.Entry;
+import java.util.Optional;
+import java.util.Set;
+import java.util.stream.Collectors;
+
import org.cloudfoundry.identity.uaa.authentication.UaaAuthentication;
import org.cloudfoundry.identity.uaa.authentication.UaaPrincipal;
-import org.cloudfoundry.identity.uaa.authentication.event.UserAuthenticationSuccessEvent;
+import org.cloudfoundry.identity.uaa.authentication.event.IdentityProviderAuthenticationSuccessEvent;
import org.cloudfoundry.identity.uaa.authentication.manager.ExternalGroupAuthorizationEvent;
import org.cloudfoundry.identity.uaa.authentication.manager.InvitedUserAuthenticatedEvent;
import org.cloudfoundry.identity.uaa.authentication.manager.NewUserAuthenticatedEvent;
@@ -37,6 +46,10 @@
import org.cloudfoundry.identity.uaa.web.UaaSavedRequestAwareAuthenticationSuccessHandler;
import org.cloudfoundry.identity.uaa.zone.IdentityZone;
import org.cloudfoundry.identity.uaa.zone.IdentityZoneHolder;
+
+import org.apache.commons.lang.StringUtils;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
import org.joda.time.DateTime;
import org.opensaml.saml2.core.Attribute;
import org.opensaml.saml2.core.AuthnStatement;
@@ -72,18 +85,6 @@
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
-import javax.xml.namespace.QName;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Date;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map.Entry;
-import java.util.Optional;
-import java.util.Set;
-import java.util.stream.Collectors;
-
import static org.cloudfoundry.identity.uaa.provider.ExternalIdentityProviderDefinition.EMAIL_ATTRIBUTE_NAME;
import static org.cloudfoundry.identity.uaa.provider.ExternalIdentityProviderDefinition.FAMILY_NAME_ATTRIBUTE_NAME;
import static org.cloudfoundry.identity.uaa.provider.ExternalIdentityProviderDefinition.GIVEN_NAME_ATTRIBUTE_NAME;
@@ -173,7 +174,7 @@ public Authentication authenticate(Authentication authentication) throws Authent
UaaUser user = createIfMissing(samlPrincipal, addNew, authorities, userAttributes);
UaaPrincipal principal = new UaaPrincipal(user);
UaaAuthentication resultUaaAuthentication = new LoginSamlAuthenticationToken(principal, result).getUaaAuthentication(user.getAuthorities(), filteredExternalGroups, userAttributes);
- publish(new UserAuthenticationSuccessEvent(user, resultUaaAuthentication));
+ publish(new IdentityProviderAuthenticationSuccessEvent(user, resultUaaAuthentication));
if (samlConfig.isStoreCustomAttributes()) {
userDatabase.storeUserInfo(user.getId(),
new UserInfo()
diff --git a/server/src/main/resources/spring/login-ui.xml b/server/src/main/resources/spring/login-ui.xml
index c1fb16cc9ba..babeba23dbb 100644
--- a/server/src/main/resources/spring/login-ui.xml
+++ b/server/src/main/resources/spring/login-ui.xml
@@ -214,11 +214,16 @@
+
+
+
+
+
+ * This product is licensed to you under the Apache License, Version 2.0 (the "License").
+ * You may not use this product except in compliance with the License.
+ *
+ * This product includes a number of subcomponents with
+ * separate copyright notices and license terms. Your use of these
+ * subcomponents is subject to the terms and conditions of the
+ * subcomponent's license, as noted in the LICENSE file
+ */
+
+package org.cloudfoundry.identity.uaa.authentication.listener;
+
+import org.cloudfoundry.identity.uaa.authentication.UaaAuthentication;
+import org.cloudfoundry.identity.uaa.authentication.event.IdentityProviderAuthenticationSuccessEvent;
+import org.cloudfoundry.identity.uaa.authentication.event.MfaAuthenticationSuccessEvent;
+import org.cloudfoundry.identity.uaa.authentication.event.UserAuthenticationSuccessEvent;
+import org.cloudfoundry.identity.uaa.mfa.MfaChecker;
+import org.cloudfoundry.identity.uaa.scim.ScimUser;
+import org.cloudfoundry.identity.uaa.scim.ScimUserProvisioning;
+import org.cloudfoundry.identity.uaa.user.UaaUser;
+import org.cloudfoundry.identity.uaa.user.UaaUserPrototype;
+import org.cloudfoundry.identity.uaa.zone.IdentityZoneHolder;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.springframework.context.ApplicationEventPublisher;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.isA;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyZeroInteractions;
+import static org.mockito.Mockito.when;
+
+public class AuthenticationSuccessListenerTests {
+
+ AuthenticationSuccessListener listener;
+ ScimUserProvisioning scimUserProvisioning;
+ UaaAuthentication mockAuth = mock(UaaAuthentication.class);
+ MfaChecker checker;
+ ApplicationEventPublisher publisher;
+ private String id;
+ private UaaUserPrototype userPrototype;
+ private UaaUser user;
+
+ @Before
+ public void setUp() {
+ publisher = mock(ApplicationEventPublisher.class);
+ checker = mock(MfaChecker.class);
+ scimUserProvisioning = mock(ScimUserProvisioning.class);
+ listener = new AuthenticationSuccessListener(scimUserProvisioning, checker);
+ listener.setApplicationEventPublisher(publisher);
+ id = "user-id";
+ userPrototype = new UaaUserPrototype()
+ .withId(id)
+ .withUsername("testUser")
+ .withEmail("test@email.com");
+ user = new UaaUser(userPrototype);
+ }
+
+ private ScimUser getScimUser(UaaUser user) {
+ ScimUser scimUser = new ScimUser(user.getId(), user.getUsername(), user.getGivenName(), user.getFamilyName());
+ scimUser.setVerified(user.isVerified());
+ return scimUser;
+ }
+
+ @Test
+ public void unverifiedUserBecomesVerifiedIfTheyHaveLegacyFlag() {
+ userPrototype
+ .withVerified(false)
+ .withLegacyVerificationBehavior(true);
+ UserAuthenticationSuccessEvent event = getEvent();
+ String zoneId = IdentityZoneHolder.get().getId();
+ when(scimUserProvisioning.retrieve(id, zoneId)).thenReturn(getScimUser(event.getUser()));
+ listener.onApplicationEvent(event);
+ verify(scimUserProvisioning).verifyUser(eq(id), eq(-1), eq(zoneId));
+ }
+
+ public UserAuthenticationSuccessEvent getEvent() {
+ user = new UaaUser(userPrototype);
+ return new UserAuthenticationSuccessEvent(
+ user,
+ mockAuth
+ );
+ }
+
+ @Test
+ public void unverifiedUserDoesNotBecomeVerifiedIfTheyHaveNoLegacyFlag() {
+ userPrototype.withVerified(false);
+ UserAuthenticationSuccessEvent event = getEvent();
+ String zoneId = IdentityZoneHolder.get().getId();
+ when(scimUserProvisioning.retrieve(id, zoneId)).thenReturn(getScimUser(event.getUser()));
+ listener.onApplicationEvent(event);
+ verify(scimUserProvisioning, never()).verifyUser(anyString(), anyInt(), eq(zoneId));
+ }
+
+ @Test
+ public void userLastUpdatedGetsCalledOnEvent() {
+
+ UserAuthenticationSuccessEvent event = getEvent();
+ when(scimUserProvisioning.retrieve(id, IdentityZoneHolder.get().getId())).thenReturn(getScimUser(event.getUser()));
+ listener.onApplicationEvent(event);
+ verify(scimUserProvisioning, times(1)).updateLastLogonTime(id, IdentityZoneHolder.get().getId());
+ }
+
+ @Test
+ public void previousLoginIsSetOnTheAuthentication() {
+ userPrototype
+ .withLastLogonSuccess(123456789L);
+ UserAuthenticationSuccessEvent event = getEvent();
+ String zoneId = IdentityZoneHolder.get().getId();
+ when(scimUserProvisioning.retrieve(this.id, zoneId)).thenReturn(getScimUser(event.getUser()));
+ UaaAuthentication authentication = (UaaAuthentication) event.getAuthentication();
+ listener.onApplicationEvent(event);
+ verify(authentication).setLastLoginSuccessTime(123456789L);
+ }
+
+ @Test
+ public void provider_authentication_success_triggers_user_authentication_success() throws Exception {
+ when(checker.isMfaEnabled(any(), any())).thenReturn(false);
+ IdentityProviderAuthenticationSuccessEvent event = new IdentityProviderAuthenticationSuccessEvent(
+ user,
+ mockAuth
+ );
+ listener.onApplicationEvent(event);
+ verify(publisher, times(1)).publishEvent(isA(UserAuthenticationSuccessEvent.class));
+ }
+
+ @Test
+ public void provider_authentication_success_does_not_trigger_user_authentication_success() throws Exception {
+ when(checker.isMfaEnabled(any(), any())).thenReturn(true);
+ IdentityProviderAuthenticationSuccessEvent event = new IdentityProviderAuthenticationSuccessEvent(
+ user,
+ mockAuth
+ );
+ listener.onApplicationEvent(event);
+ verifyZeroInteractions(publisher);
+ }
+
+ @Test
+ public void mfa_authentication_success_triggers_user_authentication_success() throws Exception {
+ when(checker.isMfaEnabled(any(), any())).thenReturn(true);
+ MfaAuthenticationSuccessEvent event = new MfaAuthenticationSuccessEvent(
+ user,
+ mockAuth,
+ "mfa-type"
+ );
+ listener.onApplicationEvent(event);
+ verify(publisher, times(1)).publishEvent(isA(UserAuthenticationSuccessEvent.class));
+ }
+
+}
diff --git a/server/src/test/java/org/cloudfoundry/identity/uaa/authentication/listener/UserAuthenticationSuccessListenerTests.java b/server/src/test/java/org/cloudfoundry/identity/uaa/authentication/listener/UserAuthenticationSuccessListenerTests.java
deleted file mode 100644
index 81bfa683eb0..00000000000
--- a/server/src/test/java/org/cloudfoundry/identity/uaa/authentication/listener/UserAuthenticationSuccessListenerTests.java
+++ /dev/null
@@ -1,120 +0,0 @@
-package org.cloudfoundry.identity.uaa.authentication.listener;
-
-import org.cloudfoundry.identity.uaa.authentication.UaaAuthentication;
-import org.cloudfoundry.identity.uaa.authentication.event.UserAuthenticationSuccessEvent;
-import org.cloudfoundry.identity.uaa.scim.ScimUser;
-import org.cloudfoundry.identity.uaa.scim.ScimUserProvisioning;
-import org.cloudfoundry.identity.uaa.user.UaaUser;
-import org.cloudfoundry.identity.uaa.user.UaaUserPrototype;
-import org.cloudfoundry.identity.uaa.zone.IdentityZoneHolder;
-import org.junit.Before;
-import org.junit.Test;
-
-import static org.mockito.Matchers.anyInt;
-import static org.mockito.Matchers.anyString;
-import static org.mockito.Matchers.eq;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-/*******************************************************************************
- * Cloud Foundry
- * Copyright (c) [2009-2015] Pivotal Software, Inc. All Rights Reserved.
- *
- * This product is licensed to you under the Apache License, Version 2.0 (the "License").
- * You may not use this product except in compliance with the License.
- *
- * This product includes a number of subcomponents with
- * separate copyright notices and license terms. Your use of these
- * subcomponents is subject to the terms and conditions of the
- * subcomponent's license, as noted in the LICENSE file.
- *******************************************************************************/
-public class UserAuthenticationSuccessListenerTests {
-
- UserAuthenticationSuccessListener listener;
- ScimUserProvisioning scimUserProvisioning;
- UaaAuthentication mockAuth = mock(UaaAuthentication.class);
- @Before
- public void SetUp()
- {
- scimUserProvisioning = mock(ScimUserProvisioning.class);
- listener = new UserAuthenticationSuccessListener(scimUserProvisioning);
- }
-
- private UserAuthenticationSuccessEvent getEvent(UaaUserPrototype userPrototype) {
- return new UserAuthenticationSuccessEvent(new UaaUser(userPrototype), mockAuth);
- }
-
- private ScimUser getScimUser(UaaUser user) {
- ScimUser scimUser = new ScimUser(user.getId(), user.getUsername(), user.getGivenName(), user.getFamilyName());
- scimUser.setVerified(user.isVerified());
- return scimUser;
- }
-
- @Test
- public void unverifiedUserBecomesVerifiedIfTheyHaveLegacyFlag() {
- String id = "user-id";
- UserAuthenticationSuccessEvent event = getEvent(new UaaUserPrototype()
- .withId(id)
- .withUsername("testUser")
- .withEmail("test@email.com")
- .withVerified(false)
- .withLegacyVerificationBehavior(true));
- String zoneId = IdentityZoneHolder.get().getId();
- when(scimUserProvisioning.retrieve(id, zoneId)).thenReturn(getScimUser(event.getUser()));
-
- listener.onApplicationEvent(event);
-
- verify(scimUserProvisioning).verifyUser(eq(id), eq(-1), eq(zoneId));
- }
-
- @Test
- public void unverifiedUserDoesNotBecomeVerifiedIfTheyHaveNoLegacyFlag() {
- String id = "user-id";
- UserAuthenticationSuccessEvent event = getEvent(new UaaUserPrototype()
- .withId(id)
- .withUsername("testUser")
- .withEmail("test@email.com")
- .withVerified(false));
- String zoneId = IdentityZoneHolder.get().getId();
- when(scimUserProvisioning.retrieve(id, zoneId)).thenReturn(getScimUser(event.getUser()));
-
- listener.onApplicationEvent(event);
-
- verify(scimUserProvisioning, never()).verifyUser(anyString(), anyInt(), eq(zoneId));
- }
-
- @Test
- public void userLastUpdatedGetsCalledOnEvent() {
- String userId = "userId";
- UserAuthenticationSuccessEvent event = getEvent(new UaaUserPrototype()
- .withId(userId)
- .withEmail("test@test.org")
- .withUsername("testUser")
- .withVerified(false));
- when(scimUserProvisioning.retrieve(userId, IdentityZoneHolder.get().getId())).thenReturn(getScimUser(event.getUser()));
-
- listener.onApplicationEvent(event);
- verify(scimUserProvisioning, times(1)).updateLastLogonTime(userId, IdentityZoneHolder.get().getId());
- }
-
- @Test
- public void previousLoginIsSetOnTheAuthentication() {
- String userId = "userId";
- UaaUserPrototype uaaUserPrototype = new UaaUserPrototype()
- .withId(userId)
- .withEmail("test@test.org")
- .withUsername("testUser")
- .withVerified(false)
- .withLastLogonSuccess(123456789L);
-
- UserAuthenticationSuccessEvent event = new UserAuthenticationSuccessEvent(new UaaUser(uaaUserPrototype), mockAuth);
- when(scimUserProvisioning.retrieve(userId, IdentityZoneHolder.get().getId())).thenReturn(getScimUser(event.getUser()));
- UaaAuthentication authentication = (UaaAuthentication) event.getAuthentication();
- listener.onApplicationEvent(event);
- verify(authentication).setLastLoginSuccessTime(123456789L);
- }
-
-}
diff --git a/server/src/test/java/org/cloudfoundry/identity/uaa/authentication/manager/AuthzAuthenticationManagerTests.java b/server/src/test/java/org/cloudfoundry/identity/uaa/authentication/manager/AuthzAuthenticationManagerTests.java
index 5547ee511a2..2cab4306c54 100644
--- a/server/src/test/java/org/cloudfoundry/identity/uaa/authentication/manager/AuthzAuthenticationManagerTests.java
+++ b/server/src/test/java/org/cloudfoundry/identity/uaa/authentication/manager/AuthzAuthenticationManagerTests.java
@@ -12,17 +12,23 @@
*******************************************************************************/
package org.cloudfoundry.identity.uaa.authentication.manager;
+import javax.servlet.http.HttpServletRequest;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
import org.cloudfoundry.identity.uaa.authentication.AccountNotVerifiedException;
import org.cloudfoundry.identity.uaa.authentication.AuthenticationPolicyRejectionException;
import org.cloudfoundry.identity.uaa.authentication.AuthzAuthenticationRequest;
import org.cloudfoundry.identity.uaa.authentication.UaaAuthentication;
import org.cloudfoundry.identity.uaa.authentication.UaaAuthenticationDetails;
import org.cloudfoundry.identity.uaa.authentication.UaaPrincipal;
+import org.cloudfoundry.identity.uaa.authentication.event.IdentityProviderAuthenticationSuccessEvent;
import org.cloudfoundry.identity.uaa.authentication.event.PasswordAuthenticationFailureEvent;
-import org.cloudfoundry.identity.uaa.authentication.event.PasswordAuthenticationSuccessEvent;
import org.cloudfoundry.identity.uaa.authentication.event.UnverifiedUserAuthenticationEvent;
import org.cloudfoundry.identity.uaa.authentication.event.UserAuthenticationFailureEvent;
-import org.cloudfoundry.identity.uaa.authentication.event.UserAuthenticationSuccessEvent;
import org.cloudfoundry.identity.uaa.authentication.event.UserNotFoundEvent;
import org.cloudfoundry.identity.uaa.constants.OriginKeys;
import org.cloudfoundry.identity.uaa.provider.IdentityProvider;
@@ -34,6 +40,7 @@
import org.cloudfoundry.identity.uaa.user.UaaUserDatabase;
import org.cloudfoundry.identity.uaa.user.UaaUserPrototype;
import org.cloudfoundry.identity.uaa.zone.IdentityZoneHolder;
+
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
@@ -49,13 +56,6 @@
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.oauth2.common.util.RandomValueStringGenerator;
-import javax.servlet.http.HttpServletRequest;
-import java.util.Calendar;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
import static org.hamcrest.Matchers.containsInAnyOrder;
import static org.hamcrest.Matchers.instanceOf;
import static org.junit.Assert.assertEquals;
@@ -136,11 +136,8 @@ public void successfulAuthentication() throws Exception {
assertThat(((UaaAuthentication)result).getAuthenticationMethods(), containsInAnyOrder("pwd"));
List events = eventCaptor.getAllValues();
- assertThat(events.get(0), instanceOf(PasswordAuthenticationSuccessEvent.class));
- assertEquals("auser", ((PasswordAuthenticationSuccessEvent)events.get(0)).getUser().getUsername());
- assertThat(events.get(1), instanceOf(UserAuthenticationSuccessEvent.class));
- assertEquals("auser", ((UserAuthenticationSuccessEvent)events.get(1)).getUser().getUsername());
-
+ assertThat(events.get(0), instanceOf(IdentityProviderAuthenticationSuccessEvent.class));
+ assertEquals("auser", ((IdentityProviderAuthenticationSuccessEvent)events.get(0)).getUser().getUsername());
}
@Test
@@ -199,8 +196,7 @@ public void successfulAuthenticationReturnsTokenAndPublishesEvent() throws Excep
assertEquals("auser", result.getName());
assertEquals("auser", ((UaaPrincipal) result.getPrincipal()).getName());
- verify(publisher).publishEvent(isA(PasswordAuthenticationSuccessEvent.class));
- verify(publisher).publishEvent(isA(UserAuthenticationSuccessEvent.class));
+ verify(publisher).publishEvent(isA(IdentityProviderAuthenticationSuccessEvent.class));
}
@Test
diff --git a/server/src/test/java/org/cloudfoundry/identity/uaa/authentication/manager/ExternalLoginAuthenticationManagerTest.java b/server/src/test/java/org/cloudfoundry/identity/uaa/authentication/manager/ExternalLoginAuthenticationManagerTest.java
index 1d919b93e74..90c445d0f8b 100644
--- a/server/src/test/java/org/cloudfoundry/identity/uaa/authentication/manager/ExternalLoginAuthenticationManagerTest.java
+++ b/server/src/test/java/org/cloudfoundry/identity/uaa/authentication/manager/ExternalLoginAuthenticationManagerTest.java
@@ -1,10 +1,15 @@
package org.cloudfoundry.identity.uaa.authentication.manager;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+
import org.cloudfoundry.identity.uaa.authentication.AccountNotPreCreatedException;
import org.cloudfoundry.identity.uaa.authentication.UaaAuthentication;
import org.cloudfoundry.identity.uaa.authentication.UaaAuthenticationDetails;
import org.cloudfoundry.identity.uaa.authentication.UaaPrincipal;
-import org.cloudfoundry.identity.uaa.authentication.event.UserAuthenticationSuccessEvent;
+import org.cloudfoundry.identity.uaa.authentication.event.IdentityProviderAuthenticationSuccessEvent;
import org.cloudfoundry.identity.uaa.provider.ExternalIdentityProviderDefinition;
import org.cloudfoundry.identity.uaa.provider.IdentityProvider;
import org.cloudfoundry.identity.uaa.provider.IdentityProviderProvisioning;
@@ -15,6 +20,7 @@
import org.cloudfoundry.identity.uaa.user.UaaUserDatabase;
import org.cloudfoundry.identity.uaa.user.UaaUserPrototype;
import org.cloudfoundry.identity.uaa.user.UserInfo;
+
import org.junit.Before;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
@@ -30,11 +36,6 @@
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-
import static org.cloudfoundry.identity.uaa.constants.OriginKeys.LDAP;
import static org.hamcrest.CoreMatchers.containsString;
import static org.junit.Assert.assertEquals;
@@ -496,7 +497,7 @@ public void testAuthenticateUserExists() throws Exception {
userArgumentCaptor = ArgumentCaptor.forClass(ApplicationEvent.class);
verify(applicationEventPublisher,times(1)).publishEvent(userArgumentCaptor.capture());
assertEquals(1,userArgumentCaptor.getAllValues().size());
- UserAuthenticationSuccessEvent userevent = (UserAuthenticationSuccessEvent)userArgumentCaptor.getAllValues().get(0);
+ IdentityProviderAuthenticationSuccessEvent userevent = (IdentityProviderAuthenticationSuccessEvent)userArgumentCaptor.getAllValues().get(0);
assertEquals(origin, userevent.getUser().getOrigin());
assertEquals(userName, userevent.getUser().getUsername());
}
diff --git a/server/src/test/java/org/cloudfoundry/identity/uaa/authentication/manager/LoginAuthenticationManagerTests.java b/server/src/test/java/org/cloudfoundry/identity/uaa/authentication/manager/LoginAuthenticationManagerTests.java
index fbdb25cc7e5..1a636edbeef 100644
--- a/server/src/test/java/org/cloudfoundry/identity/uaa/authentication/manager/LoginAuthenticationManagerTests.java
+++ b/server/src/test/java/org/cloudfoundry/identity/uaa/authentication/manager/LoginAuthenticationManagerTests.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Cloud Foundry
+ * Cloud Foundry
* Copyright (c) [2009-2016] Pivotal Software, Inc. All Rights Reserved.
*
* This product is licensed to you under the Apache License, Version 2.0 (the "License").
@@ -13,10 +13,6 @@
package org.cloudfoundry.identity.uaa.authentication.manager;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertNotNull;
-
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
@@ -24,12 +20,13 @@
import org.cloudfoundry.identity.uaa.authentication.AuthzAuthenticationRequest;
import org.cloudfoundry.identity.uaa.authentication.UaaAuthenticationTestFactory;
import org.cloudfoundry.identity.uaa.authentication.UaaPrincipal;
-import org.cloudfoundry.identity.uaa.authentication.event.UserAuthenticationSuccessEvent;
+import org.cloudfoundry.identity.uaa.authentication.event.IdentityProviderAuthenticationSuccessEvent;
import org.cloudfoundry.identity.uaa.constants.OriginKeys;
import org.cloudfoundry.identity.uaa.test.TestApplicationEventPublisher;
import org.cloudfoundry.identity.uaa.user.UaaUser;
import org.cloudfoundry.identity.uaa.user.UaaUserDatabase;
import org.cloudfoundry.identity.uaa.user.UaaUserTestFactory;
+
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
@@ -46,9 +43,13 @@
import org.springframework.security.oauth2.provider.AuthorizationRequest;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+
/**
* @author Dave Syer
- *
+ *
*/
public class LoginAuthenticationManagerTests {
@@ -58,14 +59,14 @@ public class LoginAuthenticationManagerTests {
private OAuth2Authentication oauth2Authentication;
- private TestApplicationEventPublisher publisher;
+ private TestApplicationEventPublisher publisher;
@Rule
public ExpectedException expectedException = ExpectedException.none();
@Before
public void init() {
- publisher = TestApplicationEventPublisher.forEventClass(UserAuthenticationSuccessEvent.class);
+ publisher = TestApplicationEventPublisher.forEventClass(IdentityProviderAuthenticationSuccessEvent.class);
manager.setApplicationEventPublisher(publisher);
manager.setUserDatabase(userDatabase);
oauth2Authentication = new OAuth2Authentication(new AuthorizationRequest("client", Arrays.asList("read",
diff --git a/server/src/test/java/org/cloudfoundry/identity/uaa/mfa/MfaCheckerTests.java b/server/src/test/java/org/cloudfoundry/identity/uaa/mfa/MfaCheckerTests.java
new file mode 100644
index 00000000000..b345610fbff
--- /dev/null
+++ b/server/src/test/java/org/cloudfoundry/identity/uaa/mfa/MfaCheckerTests.java
@@ -0,0 +1,52 @@
+/*
+ * Cloud Foundry
+ * Copyright (c) [2009-2018] Pivotal Software, Inc. All Rights Reserved.
+ *
+ * This product is licensed to you under the Apache License, Version 2.0 (the "License").
+ * You may not use this product except in compliance with the License.
+ *
+ * This product includes a number of subcomponents with
+ * separate copyright notices and license terms. Your use of these
+ * subcomponents is subject to the terms and conditions of the
+ * subcomponent's license, as noted in the LICENSE file
+ */
+
+package org.cloudfoundry.identity.uaa.mfa;
+
+import org.cloudfoundry.identity.uaa.provider.IdentityProviderProvisioning;
+import org.cloudfoundry.identity.uaa.zone.IdentityZone;
+import org.cloudfoundry.identity.uaa.zone.MultitenancyFixture;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import static org.cloudfoundry.identity.uaa.constants.OriginKeys.UAA;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
+
+public class MfaCheckerTests {
+
+ private IdentityZone zone;
+ private MfaChecker checker;
+ private IdentityProviderProvisioning providerProvisioning;
+
+ @Before
+ public void setUp() throws Exception {
+ providerProvisioning = mock(IdentityProviderProvisioning.class);
+ zone = MultitenancyFixture.identityZone("id", "domain");
+ checker = new MfaChecker(providerProvisioning);
+ }
+
+ @Test
+ public void mfa_zone_enabled() {
+ zone.getConfig().getMfaConfig().setEnabled(true);
+ assertTrue(checker.isMfaEnabled(zone, UAA));
+ }
+
+ @Test
+ public void mfa_zone_disabled() {
+ zone.getConfig().getMfaConfig().setEnabled(false);
+ assertFalse(checker.isMfaEnabled(zone, UAA));
+ }
+}
\ No newline at end of file
diff --git a/server/src/test/java/org/cloudfoundry/identity/uaa/mfa/MfaRequiredFilterTests.java b/server/src/test/java/org/cloudfoundry/identity/uaa/mfa/MfaRequiredFilterTests.java
index a1a7b33b481..caf5d995b3e 100644
--- a/server/src/test/java/org/cloudfoundry/identity/uaa/mfa/MfaRequiredFilterTests.java
+++ b/server/src/test/java/org/cloudfoundry/identity/uaa/mfa/MfaRequiredFilterTests.java
@@ -23,6 +23,7 @@
import org.cloudfoundry.identity.uaa.authentication.UaaAuthentication;
import org.cloudfoundry.identity.uaa.authentication.UaaPrincipal;
+import org.cloudfoundry.identity.uaa.provider.IdentityProviderProvisioning;
import org.cloudfoundry.identity.uaa.zone.IdentityZoneHolder;
import org.junit.After;
@@ -46,11 +47,9 @@
import static org.cloudfoundry.identity.uaa.mfa.MfaRequiredFilter.MfaNextStep.MFA_REQUIRED;
import static org.cloudfoundry.identity.uaa.mfa.MfaRequiredFilter.MfaNextStep.NOT_AUTHENTICATED;
import static org.hamcrest.Matchers.containsString;
-import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertThat;
-import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.same;
@@ -72,14 +71,17 @@ public class MfaRequiredFilterTests {
private HttpServletResponse response;
private FilterChain chain;
private MfaRequiredFilter filter;
+ private IdentityProviderProvisioning providerProvisioning;
@Before
public void setup() throws Exception {
+ providerProvisioning = mock(IdentityProviderProvisioning.class);
requestCache = mock(RequestCache.class);
filter = new MfaRequiredFilter("/login/mfa/**",
"/login/mfa/register",
requestCache,
- "/login/mfa/completed");
+ "/login/mfa/completed",
+ new MfaChecker(providerProvisioning));
spyFilter = spy(filter);
request = new MockHttpServletRequest();
usernameAuthentication = new UsernamePasswordAuthenticationToken("fake-principal","fake-credentials");
@@ -100,17 +102,6 @@ public void teardown() throws Exception {
SecurityContextHolder.clearContext();
}
- @Test
- public void mfa_not_required() throws Exception {
- assertFalse(spyFilter.mfaRequired());
- }
-
- @Test
- public void mfa_required() throws Exception {
- IdentityZoneHolder.get().getConfig().getMfaConfig().setEnabled(true);
- assertTrue(spyFilter.mfaRequired());
- }
-
@Test
public void authentication_log_info_null() throws Exception {
assertNull(spyFilter.getAuthenticationLogInfo());
diff --git a/server/src/test/java/org/cloudfoundry/identity/uaa/provider/saml/LoginSamlAuthenticationProviderTests.java b/server/src/test/java/org/cloudfoundry/identity/uaa/provider/saml/LoginSamlAuthenticationProviderTests.java
index f9011b3f248..cdee3830f6a 100644
--- a/server/src/test/java/org/cloudfoundry/identity/uaa/provider/saml/LoginSamlAuthenticationProviderTests.java
+++ b/server/src/test/java/org/cloudfoundry/identity/uaa/provider/saml/LoginSamlAuthenticationProviderTests.java
@@ -15,8 +15,18 @@
package org.cloudfoundry.identity.uaa.provider.saml;
+import javax.servlet.ServletContext;
+import javax.xml.namespace.QName;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
import org.cloudfoundry.identity.uaa.authentication.UaaAuthentication;
-import org.cloudfoundry.identity.uaa.authentication.event.UserAuthenticationSuccessEvent;
+import org.cloudfoundry.identity.uaa.authentication.event.IdentityProviderAuthenticationSuccessEvent;
import org.cloudfoundry.identity.uaa.authentication.manager.AuthEvent;
import org.cloudfoundry.identity.uaa.constants.OriginKeys;
import org.cloudfoundry.identity.uaa.provider.IdentityProvider;
@@ -42,6 +52,7 @@
import org.cloudfoundry.identity.uaa.web.UaaSavedRequestAwareAuthenticationSuccessHandler;
import org.cloudfoundry.identity.uaa.zone.IdentityZone;
import org.cloudfoundry.identity.uaa.zone.IdentityZoneHolder;
+
import org.joda.time.DateTime;
import org.junit.After;
import org.junit.Before;
@@ -84,16 +95,6 @@
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.context.request.ServletWebRequest;
-import javax.servlet.ServletContext;
-import javax.xml.namespace.QName;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-
import static org.cloudfoundry.identity.uaa.provider.ExternalIdentityProviderDefinition.GROUP_ATTRIBUTE_NAME;
import static org.cloudfoundry.identity.uaa.provider.ExternalIdentityProviderDefinition.USER_ATTRIBUTE_PREFIX;
import static org.hamcrest.Matchers.containsInAnyOrder;
@@ -332,7 +333,7 @@ public void testAuthenticateSimple() {
public void testAuthenticationEvents() {
authprovider.authenticate(mockSamlAuthentication(OriginKeys.SAML));
assertEquals(3, publisher.events.size());
- assertTrue(publisher.events.get(2) instanceof UserAuthenticationSuccessEvent);
+ assertTrue(publisher.events.get(2) instanceof IdentityProviderAuthenticationSuccessEvent);
}
@Test
diff --git a/uaa/src/main/webapp/WEB-INF/spring-servlet.xml b/uaa/src/main/webapp/WEB-INF/spring-servlet.xml
index ad869bd2acc..224cfb1d547 100755
--- a/uaa/src/main/webapp/WEB-INF/spring-servlet.xml
+++ b/uaa/src/main/webapp/WEB-INF/spring-servlet.xml
@@ -572,8 +572,9 @@
-
+
+
diff --git a/uaa/src/test/java/org/cloudfoundry/identity/uaa/mock/audit/AuditCheckMockMvcTests.java b/uaa/src/test/java/org/cloudfoundry/identity/uaa/mock/audit/AuditCheckMockMvcTests.java
index 578e90ad8b5..d35df3584b8 100644
--- a/uaa/src/test/java/org/cloudfoundry/identity/uaa/mock/audit/AuditCheckMockMvcTests.java
+++ b/uaa/src/test/java/org/cloudfoundry/identity/uaa/mock/audit/AuditCheckMockMvcTests.java
@@ -12,8 +12,12 @@
*******************************************************************************/
package org.cloudfoundry.identity.uaa.mock.audit;
-import com.fasterxml.jackson.core.type.TypeReference;
-import org.apache.commons.codec.binary.Base64;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
import org.cloudfoundry.identity.uaa.account.LostPasswordChangeRequest;
import org.cloudfoundry.identity.uaa.account.event.PasswordChangeEvent;
import org.cloudfoundry.identity.uaa.account.event.PasswordChangeFailureEvent;
@@ -30,8 +34,8 @@
import org.cloudfoundry.identity.uaa.authentication.UaaAuthenticationDetails;
import org.cloudfoundry.identity.uaa.authentication.event.ClientAuthenticationFailureEvent;
import org.cloudfoundry.identity.uaa.authentication.event.ClientAuthenticationSuccessEvent;
+import org.cloudfoundry.identity.uaa.authentication.event.IdentityProviderAuthenticationSuccessEvent;
import org.cloudfoundry.identity.uaa.authentication.event.PasswordAuthenticationFailureEvent;
-import org.cloudfoundry.identity.uaa.authentication.event.PasswordAuthenticationSuccessEvent;
import org.cloudfoundry.identity.uaa.authentication.event.PrincipalAuthenticationFailureEvent;
import org.cloudfoundry.identity.uaa.authentication.event.UnverifiedUserAuthenticationEvent;
import org.cloudfoundry.identity.uaa.authentication.event.UserAuthenticationFailureEvent;
@@ -56,6 +60,9 @@
import org.cloudfoundry.identity.uaa.zone.ClientServicesExtension;
import org.cloudfoundry.identity.uaa.zone.IdentityZoneHolder;
import org.cloudfoundry.identity.uaa.zone.MultitenantJdbcClientDetailsService;
+
+import com.fasterxml.jackson.core.type.TypeReference;
+import org.apache.commons.codec.binary.Base64;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
@@ -75,16 +82,11 @@
import org.springframework.test.web.servlet.ResultActions;
import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.List;
-import java.util.Map;
-import java.util.stream.Collectors;
-
import static org.cloudfoundry.identity.uaa.audit.AuditEventType.ClientCreateSuccess;
import static org.cloudfoundry.identity.uaa.audit.AuditEventType.ClientUpdateSuccess;
import static org.cloudfoundry.identity.uaa.audit.AuditEventType.GroupCreatedEvent;
import static org.cloudfoundry.identity.uaa.mock.util.MockMvcUtils.CookieCsrfPostProcessor.cookieCsrf;
+import static org.cloudfoundry.identity.uaa.mock.util.MockMvcUtils.getEventOfType;
import static org.hamcrest.Matchers.containsInAnyOrder;
import static org.hamcrest.Matchers.containsString;
import static org.junit.Assert.assertEquals;
@@ -256,10 +258,10 @@ public void userLoginTest() throws Exception {
ArgumentCaptor captor = ArgumentCaptor.forClass(AbstractUaaEvent.class);
verify(listener, times(2)).onApplicationEvent(captor.capture());
- PasswordAuthenticationSuccessEvent passwordevent = (PasswordAuthenticationSuccessEvent)captor.getAllValues().get(0);
+ IdentityProviderAuthenticationSuccessEvent passwordevent = getEventOfType(captor, IdentityProviderAuthenticationSuccessEvent.class);
assertEquals(testUser.getUserName(), passwordevent.getUser().getUsername());
assertTrue(passwordevent.getAuditEvent().getOrigin().contains("sessionId="));
- UserAuthenticationSuccessEvent userevent = (UserAuthenticationSuccessEvent)captor.getAllValues().get(1);
+ UserAuthenticationSuccessEvent userevent = getEventOfType(captor, UserAuthenticationSuccessEvent.class);
assertEquals(passwordevent.getUser().getId(), userevent.getUser().getId());
assertEquals(testUser.getUserName(), userevent.getUser().getUsername());
assertTrue(userevent.getAuditEvent().getOrigin().contains("sessionId="));
@@ -281,10 +283,10 @@ public void userLoginAuthenticateEndpointTest() throws Exception {
ArgumentCaptor captor = ArgumentCaptor.forClass(AbstractUaaEvent.class);
verify(listener, times(2)).onApplicationEvent(captor.capture());
- PasswordAuthenticationSuccessEvent passwordevent = (PasswordAuthenticationSuccessEvent)captor.getAllValues().get(0);
+ IdentityProviderAuthenticationSuccessEvent passwordevent = getEventOfType(captor, IdentityProviderAuthenticationSuccessEvent.class);
assertEquals(testUser.getUserName(), passwordevent.getUser().getUsername());
assertTrue(passwordevent.getAuditEvent().getOrigin().contains("sessionId="));
- UserAuthenticationSuccessEvent userevent = (UserAuthenticationSuccessEvent)captor.getAllValues().get(1);
+ UserAuthenticationSuccessEvent userevent = getEventOfType(captor, UserAuthenticationSuccessEvent.class);
assertEquals(passwordevent.getUser().getId(), userevent.getUser().getId());
assertEquals(testUser.getUserName(), userevent.getUser().getUsername());
assertTrue(userevent.getAuditEvent().getOrigin().contains("sessionId="));
@@ -502,10 +504,10 @@ public void userChangePasswordTest() throws Exception {
.andExpect(header().string("Location", "/"));
ArgumentCaptor captor = ArgumentCaptor.forClass(AbstractUaaEvent.class);
verify(listener, times(2)).onApplicationEvent(captor.capture());
- PasswordAuthenticationSuccessEvent passwordevent = (PasswordAuthenticationSuccessEvent)captor.getAllValues().get(0);
+ IdentityProviderAuthenticationSuccessEvent passwordevent = getEventOfType(captor, IdentityProviderAuthenticationSuccessEvent.class);
String userid = passwordevent.getUser().getId();
assertTrue(passwordevent.getAuditEvent().getOrigin().contains("sessionId="));
- UserAuthenticationSuccessEvent userevent = (UserAuthenticationSuccessEvent)captor.getAllValues().get(1);
+ UserAuthenticationSuccessEvent userevent = getEventOfType(captor, UserAuthenticationSuccessEvent.class);
assertEquals(passwordevent.getUser().getId(), userevent.getUser().getId());
assertTrue(userevent.getAuditEvent().getOrigin().contains("sessionId="));
@@ -553,10 +555,10 @@ public void userChangeInvalidPasswordTest() throws Exception {
ArgumentCaptor captor = ArgumentCaptor.forClass(AbstractUaaEvent.class);
verify(listener, times(2)).onApplicationEvent(captor.capture());
- PasswordAuthenticationSuccessEvent passwordevent = (PasswordAuthenticationSuccessEvent)captor.getAllValues().get(0);
+ IdentityProviderAuthenticationSuccessEvent passwordevent = getEventOfType(captor, IdentityProviderAuthenticationSuccessEvent.class);
String userid = passwordevent.getUser().getId();
assertTrue(passwordevent.getAuditEvent().getOrigin().contains("sessionId="));
- UserAuthenticationSuccessEvent userevent = (UserAuthenticationSuccessEvent)captor.getAllValues().get(1);
+ UserAuthenticationSuccessEvent userevent = getEventOfType(captor, UserAuthenticationSuccessEvent.class);
assertEquals(passwordevent.getUser().getId(), userevent.getUser().getId());
assertTrue(userevent.getAuditEvent().getOrigin().contains("sessionId="));
@@ -793,7 +795,7 @@ public void testUserCreatedEventDuringLoginServerAuthorize() throws Exception {
getMockMvc().perform(userPost)
.andExpect(status().isOk());
- assertEquals(2, testListener.getEventCount());
+ assertEquals(3, testListener.getEventCount());
UserModifiedEvent userModifiedEvent = (UserModifiedEvent) testListener.getEvents().get(0);
assertEquals("login", userModifiedEvent.getAuthentication().getName());
diff --git a/uaa/src/test/java/org/cloudfoundry/identity/uaa/mock/util/MockMvcUtils.java b/uaa/src/test/java/org/cloudfoundry/identity/uaa/mock/util/MockMvcUtils.java
index 97189a0050a..0d91ff59744 100644
--- a/uaa/src/test/java/org/cloudfoundry/identity/uaa/mock/util/MockMvcUtils.java
+++ b/uaa/src/test/java/org/cloudfoundry/identity/uaa/mock/util/MockMvcUtils.java
@@ -31,6 +31,7 @@
import java.util.regex.Matcher;
import java.util.regex.Pattern;
+import org.cloudfoundry.identity.uaa.audit.event.AbstractUaaEvent;
import org.cloudfoundry.identity.uaa.authentication.UaaAuthentication;
import org.cloudfoundry.identity.uaa.authentication.UaaAuthenticationDetails;
import org.cloudfoundry.identity.uaa.authentication.UaaPrincipal;
@@ -80,6 +81,7 @@
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang.RandomStringUtils;
import org.junit.Assert;
+import org.mockito.ArgumentCaptor;
import org.mockito.Mockito;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationEvent;
@@ -175,6 +177,15 @@ private MockMvcUtils() {}
"";
+ public static T getEventOfType(ArgumentCaptor captor, Class type) {
+ for (AbstractUaaEvent event : captor.getAllValues()) {
+ if (event.getClass().equals(type)) {
+ return (T)event;
+ }
+ }
+ return null;
+ }
+
public static String performMfaPostVerifyWithCode(int code, MockMvc mvc, MockHttpSession session) throws Exception {
return performMfaPostVerifyWithCode(code, mvc, session, "localhost");
}