diff --git a/src/main/java/us/kbase/auth2/lib/Authentication.java b/src/main/java/us/kbase/auth2/lib/Authentication.java index 52d613f9..aeff80b8 100644 --- a/src/main/java/us/kbase/auth2/lib/Authentication.java +++ b/src/main/java/us/kbase/auth2/lib/Authentication.java @@ -92,6 +92,7 @@ import us.kbase.auth2.lib.user.LocalUser; import us.kbase.auth2.lib.user.NewUser; import us.kbase.auth2.lib.token.IncomingToken; +import us.kbase.auth2.lib.token.MFAStatus; /** The main class for the Authentication application. * @@ -512,7 +513,7 @@ public LocalLoginResult localLogin( userName.getName()); return new LocalLoginResult(u.getUserName()); } - return new LocalLoginResult(login(u.getUserName(), tokenCtx)); + return new LocalLoginResult(login(u.getUserName(), tokenCtx, MFAStatus.UNKNOWN)); } private LocalUser getLocalUser(final UserName userName, final Password password) @@ -744,13 +745,15 @@ public void forceResetAllPasswords(final IncomingToken token) admin.getUserName().getName()); } - private NewToken login(final UserName userName, final TokenCreationContext tokenCtx) + private NewToken login( + final UserName userName, final TokenCreationContext tokenCtx, final MFAStatus mfa) throws AuthStorageException { final NewToken nt = new NewToken(StoredToken.getBuilder( TokenType.LOGIN, randGen.randomUUID(), userName) .withLifeTime(clock.instant(), cfg.getAppConfig().getTokenLifetimeMS(TokenLifetimeType.LOGIN)) .withContext(tokenCtx) + .withMFA(mfa) .build(), randGen.getToken()); storage.storeToken(nt.getStoredToken(), nt.getTokenHash()); @@ -1795,9 +1798,11 @@ public LoginToken login( // enough args here to start considering a builder final LoginState lstate = getLoginState(ipr.getIdentities(), Instant.MIN); final ProviderConfig pc = cfg.getAppConfig().getProviderConfig(idp.getProviderName()); final LoginToken loginToken; - if (lstate.getUsers().size() == 1 && - lstate.getIdentities().isEmpty() && - !pc.isForceLoginChoice()) { + if ( + lstate.getUsers().size() == 1 + && lstate.getIdentities().isEmpty() + && !pc.isForceLoginChoice()) + { final UserName userName = lstate.getUsers().iterator().next(); final AuthUser user = lstate.getUser(userName); /* Don't throw an error here since an auth UI may not be controlling the call - @@ -1811,16 +1816,16 @@ public LoginToken login( // enough args here to start considering a builder * so who cares. */ if (!cfg.getAppConfig().isLoginAllowed() && !Role.isAdmin(user.getRoles())) { - loginToken = storeIdentitiesTemporarily(lstate); + loginToken = storeIdentitiesTemporarily(lstate, ipr.getMFA()); } else if (user.isDisabled()) { - loginToken = storeIdentitiesTemporarily(lstate); + loginToken = storeIdentitiesTemporarily(lstate, ipr.getMFA()); } else { - loginToken = new LoginToken(login(user.getUserName(), tokenCtx)); + loginToken = new LoginToken(login(user.getUserName(), tokenCtx, ipr.getMFA())); } } else { // store the identities so the user can create an account or choose from more than one // account - loginToken = storeIdentitiesTemporarily(lstate); + loginToken = storeIdentitiesTemporarily(lstate, ipr.getMFA()); } return loginToken; } @@ -1834,13 +1839,13 @@ private void checkState(final TemporarySessionData tids, final String state) } // ignores expiration date of login state - private LoginToken storeIdentitiesTemporarily(final LoginState ls) + private LoginToken storeIdentitiesTemporarily(final LoginState ls, final MFAStatus mfa) throws AuthStorageException { final Set store = new HashSet<>(ls.getIdentities()); ls.getUsers().stream().forEach(u -> store.addAll(ls.getIdentities(u))); final TemporarySessionData data = TemporarySessionData.create( randGen.randomUUID(), clock.instant(), LOGIN_TOKEN_LIFETIME_MS) - .login(store); + .login(store, mfa); final TemporaryToken tt = storeTemporarySessionData(data); logInfo("Stored temporary token {} with {} login identities", tt.getId(), store.size()); return new LoginToken(tt); @@ -1871,6 +1876,7 @@ private TemporaryToken storeTemporarySessionData(final TemporarySessionData data public LoginState getLoginState(final IncomingToken token) throws AuthStorageException, InvalidTokenException, IdentityProviderErrorException, UnauthorizedException { + // TODO CODE this ignores the MFA state. May want to add it to LoginState in the future final TemporarySessionData ids = getTemporarySessionData( Optional.empty(), Operation.LOGINIDENTS, token); logInfo("Accessed temporary login token {} with {} identities", ids.getId(), @@ -1984,11 +1990,12 @@ public NewToken createUser( if (!cfg.getAppConfig().isLoginAllowed()) { throw new UnauthorizedException("Account creation is disabled"); } - // allow mutation of the identity set - final Set ids = new HashSet<>( - getTemporarySessionData(Optional.empty(), Operation.LOGINIDENTS, token) - .getIdentities().get()); + final TemporarySessionData tsd = getTemporarySessionData( + Optional.empty(), Operation.LOGINIDENTS, token + ); storage.deleteTemporarySessionData(token.getHashedToken()); + // allow mutation of the identity set + final Set ids = new HashSet<>(tsd.getIdentities().get()); final Optional match = getIdentity(identityID, ids); if (!match.isPresent()) { throw new UnauthorizedException(String.format( @@ -2020,7 +2027,7 @@ public NewToken createUser( linked, userName.getName()); } } - return login(userName, tokenCtx); + return login(userName, tokenCtx, tsd.getMFA().get()); } /** Create a test token. The token is entirely separate from standard tokens and is @@ -2308,11 +2315,12 @@ public NewToken login( requireNonNull(policyIDs, "policyIDs"); requireNonNull(tokenCtx, "tokenCtx"); noNulls(policyIDs, "null item in policyIDs"); - // allow mutation of the identity set - final Set ids = new HashSet<>( - getTemporarySessionData(Optional.empty(), Operation.LOGINIDENTS, token) - .getIdentities().get()); + final TemporarySessionData tsd = getTemporarySessionData( + Optional.empty(), Operation.LOGINIDENTS, token + ); storage.deleteTemporarySessionData(token.getHashedToken()); + // allow mutation of the identity set + final Set ids = new HashSet<>(tsd.getIdentities().get()); final Optional ri = getIdentity(identityID, ids); if (!ri.isPresent()) { throw new UnauthorizedException(String.format( @@ -2342,7 +2350,7 @@ public NewToken login( linked, u.get().getUserName().getName()); } } - return login(u.get().getUserName(), tokenCtx); + return login(u.get().getUserName(), tokenCtx, tsd.getMFA().get()); } private Optional getIdentity( diff --git a/src/main/java/us/kbase/auth2/lib/TemporarySessionData.java b/src/main/java/us/kbase/auth2/lib/TemporarySessionData.java index a99d384d..f7bb6790 100644 --- a/src/main/java/us/kbase/auth2/lib/TemporarySessionData.java +++ b/src/main/java/us/kbase/auth2/lib/TemporarySessionData.java @@ -15,6 +15,7 @@ import us.kbase.auth2.lib.exceptions.ErrorType; import us.kbase.auth2.lib.identity.RemoteIdentity; +import us.kbase.auth2.lib.token.MFAStatus; /** Temporary session data that may include a set of temporary identities and / or an associated * user, or an error that was stored instead of the identities. @@ -33,6 +34,7 @@ public class TemporarySessionData { private final String error; private final ErrorType errorType; private final UserName user; + private final MFAStatus mfa; private TemporarySessionData( final Operation op, @@ -44,7 +46,9 @@ private TemporarySessionData( final Set identities, final UserName user, final String error, - final ErrorType errorType) { + final ErrorType errorType, + final MFAStatus mfa + ) { this.op = op; this.id = id; this.created = created; @@ -55,6 +59,7 @@ private TemporarySessionData( this.user = user; this.error = error; this.errorType = errorType; + this.mfa = mfa; } /** Get the operation this temporary session data supports. @@ -77,6 +82,13 @@ public UUID getId() { public Optional> getIdentities() { return Optional.ofNullable(identities); } + + /** Get the MFA status, if any. + * @return the MFA status. + */ + public Optional getMFA() { + return Optional.ofNullable(mfa); + } /** Get the date of creation for the session data. * @return the creation date. @@ -139,27 +151,31 @@ public boolean hasError() { @Override public int hashCode() { - return Objects.hash(created, error, errorType, expires, id, identities, oauth2State, op, pkceCodeVerifier, - user); + return Objects.hash(created, error, errorType, expires, id, identities, mfa, oauth2State, + op, pkceCodeVerifier, user + ); } @Override public boolean equals(Object obj) { - if (this == obj) { + if (this == obj) return true; - } - if (obj == null) { + if (obj == null) return false; - } - if (getClass() != obj.getClass()) { + if (getClass() != obj.getClass()) return false; - } TemporarySessionData other = (TemporarySessionData) obj; - return Objects.equals(created, other.created) && Objects.equals(error, other.error) - && errorType == other.errorType && Objects.equals(expires, other.expires) - && Objects.equals(id, other.id) && Objects.equals(identities, other.identities) - && Objects.equals(oauth2State, other.oauth2State) && op == other.op - && Objects.equals(pkceCodeVerifier, other.pkceCodeVerifier) && Objects.equals(user, other.user); + return Objects.equals(created, other.created) + && Objects.equals(error, other.error) + && errorType == other.errorType + && Objects.equals(expires, other.expires) + && Objects.equals(id, other.id) + && Objects.equals(identities, other.identities) + && mfa == other.mfa + && Objects.equals(oauth2State, other.oauth2State) + && op == other.op + && Objects.equals(pkceCodeVerifier, other.pkceCodeVerifier) + && Objects.equals(user, other.user); } /** The operation this session data is associated with. @@ -242,7 +258,7 @@ public TemporarySessionData error(final String error, final ErrorType errorType) requireNonNull(errorType, "errorType"); return new TemporarySessionData( Operation.ERROR, id, created, expires, - null, null, null, null, error, errorType); + null, null, null, null, error, errorType, null); } /** Create temporary session data for the start of a login operation. @@ -258,18 +274,32 @@ public TemporarySessionData login( checkStringNoCheckedException(pkceCodeVerifier, "pkceCodeVerifier"); return new TemporarySessionData( Operation.LOGINSTART, id, created, expires, - oauth2State, pkceCodeVerifier, null, null, null, null); + oauth2State, pkceCodeVerifier, null, null, null, null, null); } /** Create temporary session data for a login operation where remote identities are * involved. * @param identities the remote identities involved in the login. + * @param mfa the MFA state from the login. * @return the temporary session data. */ - public TemporarySessionData login(final Set identities) { + public TemporarySessionData login( + final Set identities, + final MFAStatus mfa + ) { return new TemporarySessionData( - Operation.LOGINIDENTS, id, created, expires, - null, null, checkIdents(identities), null, null, null); + Operation.LOGINIDENTS, + id, + created, + expires, + null, + null, + checkIdents(identities), + null, + null, + null, + requireNonNull(mfa, "mfa") + ); } private Set checkIdents(final Set identities) { @@ -299,7 +329,7 @@ public TemporarySessionData link( requireNonNull(userName, "userName"); return new TemporarySessionData( Operation.LINKSTART, id, created, expires, - oauth2State, pkceCodeVerifier, null, userName, null, null); + oauth2State, pkceCodeVerifier, null, userName, null, null, null); } /** Create temporary session data for a linking operation when remote identities are @@ -314,7 +344,7 @@ public TemporarySessionData link( requireNonNull(userName, "userName"); return new TemporarySessionData( Operation.LINKIDENTS, id, created, expires, - null, null, checkIdents(identities), userName, null, null); + null, null, checkIdents(identities), userName, null, null, null); } } } diff --git a/src/main/java/us/kbase/auth2/lib/storage/mongo/Fields.java b/src/main/java/us/kbase/auth2/lib/storage/mongo/Fields.java index b1ff8517..5c8ebe08 100644 --- a/src/main/java/us/kbase/auth2/lib/storage/mongo/Fields.java +++ b/src/main/java/us/kbase/auth2/lib/storage/mongo/Fields.java @@ -161,6 +161,8 @@ public class Fields { public static final String TEMP_SESSION_USER = "user"; /** The remote identities associated with the temporary token. */ public static final String TEMP_SESSION_IDENTITIES = "idents"; + /** The MFA status associated with the temporary token. */ + public static final String TEMP_SESSION_MFA = "mfa"; /** The error associated with the temporary token. */ public static final String TEMP_SESSION_ERROR = "err"; /** The type of the error associated with the temporary token. */ diff --git a/src/main/java/us/kbase/auth2/lib/storage/mongo/MongoStorage.java b/src/main/java/us/kbase/auth2/lib/storage/mongo/MongoStorage.java index c0d75ac1..72c6d2d7 100644 --- a/src/main/java/us/kbase/auth2/lib/storage/mongo/MongoStorage.java +++ b/src/main/java/us/kbase/auth2/lib/storage/mongo/MongoStorage.java @@ -1698,13 +1698,14 @@ public void storeTemporarySessionData(final TemporarySessionData data, final Str .append(Fields.TEMP_SESSION_OAUTH2STATE, data.getOAuth2State().orElse(null)) .append(Fields.TEMP_SESSION_PKCE_CODE_VERIFIER, data.getPKCECodeVerifier().orElse(null)) - .append(Fields.TEMP_SESSION_ERROR, - data.getError().isPresent() ? data.getError().get() : null) + .append(Fields.TEMP_SESSION_ERROR, data.getError().orElse(null)) .append(Fields.TEMP_SESSION_ERROR_TYPE, data.getErrorType().isPresent() ? data.getErrorType().get().getErrorCode() : null) .append(Fields.TEMP_SESSION_IDENTITIES, ids) - .append(Fields.TEMP_SESSION_USER, - data.getUser().isPresent() ? data.getUser().get().getName() : null); + .append(Fields.TEMP_SESSION_USER, data.getUser().isPresent() ? + data.getUser().get().getName() : null) + .append(Fields.TEMP_SESSION_MFA, data.getMFA().isPresent() ? + data.getMFA().get().getID() : null); storeTemporarySessionData(td); } @@ -1772,7 +1773,8 @@ public TemporarySessionData getTemporarySessionData( d.getString(Fields.TEMP_SESSION_PKCE_CODE_VERIFIER) ); } else if (op.equals(Operation.LOGINIDENTS)) { - tis = b.login(toIdentities(ids)); + final MFAStatus mfa = MFAStatus.fromID(d.getString(Fields.TEMP_SESSION_MFA)); + tis = b.login(toIdentities(ids), mfa); } else if (op.equals(Operation.LINKSTART)) { tis = b.link( d.getString(Fields.TEMP_SESSION_OAUTH2STATE), diff --git a/src/test/java/us/kbase/test/auth2/TestCommon.java b/src/test/java/us/kbase/test/auth2/TestCommon.java index f98b0db0..49128ecf 100644 --- a/src/test/java/us/kbase/test/auth2/TestCommon.java +++ b/src/test/java/us/kbase/test/auth2/TestCommon.java @@ -169,6 +169,10 @@ public static List list(T... objects) { public static final Optional ES = Optional.empty(); + public static Optional opt() { + return Optional.empty(); + } + public static Optional opt(final T obj) { return Optional.of(obj); } diff --git a/src/test/java/us/kbase/test/auth2/lib/AuthenticationLinkTest.java b/src/test/java/us/kbase/test/auth2/lib/AuthenticationLinkTest.java index 2053bc4f..9817d098 100644 --- a/src/test/java/us/kbase/test/auth2/lib/AuthenticationLinkTest.java +++ b/src/test/java/us/kbase/test/auth2/lib/AuthenticationLinkTest.java @@ -72,6 +72,7 @@ import us.kbase.auth2.lib.storage.AuthStorage; import us.kbase.auth2.lib.storage.exceptions.AuthStorageException; import us.kbase.auth2.lib.token.IncomingToken; +import us.kbase.auth2.lib.token.MFAStatus; import us.kbase.auth2.lib.token.StoredToken; import us.kbase.auth2.lib.token.TemporaryToken; import us.kbase.auth2.lib.token.TokenType; @@ -885,7 +886,7 @@ public void linkWithTokenFailBadTokenOp() throws Exception { final UUID tid = UUID.randomUUID(); when(storage.getTemporarySessionData(token.getHashedToken())).thenReturn( TemporarySessionData.create(tid, Instant.now(), Instant.now()) - .login(set(REMOTE))) + .login(set(REMOTE), MFAStatus.UNKNOWN)) .thenReturn(null); failLinkWithToken(auth, token, "prov", "foo", null, "state", new InvalidTokenException( @@ -1573,7 +1574,7 @@ public void getLinkStateFailBadTokenOp() throws Exception { when(storage.getTemporarySessionData(tempToken.getHashedToken())).thenReturn( TemporarySessionData.create(tempTokenID, NOW, NOW) - .login(set(REMOTE))) + .login(set(REMOTE), MFAStatus.UNKNOWN)) .thenReturn(null); failGetLinkState(auth, userToken, tempToken, new InvalidTokenException( @@ -1867,7 +1868,7 @@ public void linkIdentityFailBadTokenOp() throws Exception { final UUID id = UUID.randomUUID(); when(storage.getTemporarySessionData(tempToken.getHashedToken())).thenReturn( TemporarySessionData.create(id, NOW, NOW) - .login(set(REMOTE))) + .login(set(REMOTE), MFAStatus.UNKNOWN)) .thenReturn(null); failLinkIdentity(auth, userToken, tempToken, "fakeid", new InvalidTokenException( @@ -2384,7 +2385,7 @@ public void linkAllFailLinkFailBadTokenOp() throws Exception { final UUID id = UUID.randomUUID(); when(storage.getTemporarySessionData(tempToken.getHashedToken())).thenReturn( TemporarySessionData.create(id, NOW, NOW) - .login(set(REMOTE))) + .login(set(REMOTE), MFAStatus.UNKNOWN)) .thenReturn(null); failLinkAll(auth, userToken, tempToken, new InvalidTokenException( diff --git a/src/test/java/us/kbase/test/auth2/lib/AuthenticationLoginTest.java b/src/test/java/us/kbase/test/auth2/lib/AuthenticationLoginTest.java index baff074b..eb3f4bc1 100644 --- a/src/test/java/us/kbase/test/auth2/lib/AuthenticationLoginTest.java +++ b/src/test/java/us/kbase/test/auth2/lib/AuthenticationLoginTest.java @@ -81,6 +81,7 @@ import us.kbase.auth2.lib.storage.AuthStorage; import us.kbase.auth2.lib.storage.exceptions.AuthStorageException; import us.kbase.auth2.lib.token.IncomingToken; +import us.kbase.auth2.lib.token.MFAStatus; import us.kbase.auth2.lib.token.NewToken; import us.kbase.auth2.lib.token.StoredToken; import us.kbase.auth2.lib.token.TokenType; @@ -90,6 +91,8 @@ import us.kbase.test.auth2.lib.AuthenticationTester.LogEvent; import us.kbase.test.auth2.lib.AuthenticationTester.TestMocks; +// TODO CODE it seems like there's a lot of repetition in these tests, maybe could consolidate + public class AuthenticationLoginTest { private static final Instant SMALL = Instant.ofEpochMilli(1); @@ -242,93 +245,106 @@ private void loginContinueImmediately( final Role userRole, final boolean allowLogin) throws Exception { - logEvents.clear(); - - final IdentityProvider idp = mock(IdentityProvider.class); - - when(idp.getProviderName()).thenReturn("prov"); - - final TestMocks testauth = initTestMocks(set(idp)); - final AuthStorage storage = testauth.storageMock; - final RandomDataGenerator rand = testauth.randGenMock; - final Clock clock = testauth.clockMock; - final Authentication auth = testauth.auth; - - AuthenticationTester.setConfigUpdateInterval(auth, -1); - - final Map providers = ImmutableMap.of( - "prov", new ProviderConfig(true, false, false)); - - when(storage.getConfig(isA(CollectingExternalConfigMapper.class))) - .thenReturn(new AuthConfigSet( - new AuthConfig(allowLogin, providers, null), - new CollectingExternalConfig(Collections.emptyMap()))); - - final IncomingToken token = new IncomingToken("inctoken"); - - when(storage.getTemporarySessionData(token.getHashedToken())).thenReturn( - TemporarySessionData.create(UUID.randomUUID(), now(), now().plusSeconds(10)) - .login("suporstate", "pkceughherewegoagain")); - - when(idp.getIdentities("foobar", "pkceughherewegoagain", false, null)) - .thenReturn(IdentityProviderResponse.from(new RemoteIdentity( - new RemoteIdentityID("prov", "id1"), - new RemoteIdentityDetails("user1", "full1", "f@h.com")))) - .thenReturn(null); - - final RemoteIdentity storageRemoteID = new RemoteIdentity( - new RemoteIdentityID("prov", "id1"), - new RemoteIdentityDetails("user1", "full1", "f@h.com")); - - final AuthUser user = AuthUser.getBuilder(new UserName("foo"), UID, new DisplayName("bar"), - Instant.ofEpochMilli(10000L)) - .withRole(userRole) - .withIdentity(storageRemoteID).build(); - - when(storage.getUser(storageRemoteID)).thenReturn(Optional.of(user)).thenReturn(null); - - final UUID tokenID = UUID.randomUUID(); - - when(rand.randomUUID()).thenReturn(tokenID).thenReturn(null); - when(rand.getToken()).thenReturn("thisisatoken").thenReturn(null); - when(clock.instant()).thenReturn(Instant.ofEpochMilli(20000)) - .thenReturn(Instant.ofEpochMilli(30000)).thenReturn(null); - - final LoginToken lt = auth.login( - token, - "prov", - "foobar", - null, - TokenCreationContext.getBuilder().withNullableAgent("a", "v").build(), - "suporstate"); - - verify(storage).deleteTemporarySessionData(token.getHashedToken()); - - verify(storage).storeToken(StoredToken.getBuilder( - TokenType.LOGIN, tokenID, new UserName("foo")) - .withLifeTime(Instant.ofEpochMilli(20000), 14 * 24 * 3600 * 1000) - .withContext(TokenCreationContext.getBuilder() - .withNullableAgent("a", "v").build()).build(), - "rIWdQ6H23g7MLjLjJTz8k7A6zEbn6+Cnwm5anDwasLc="); - - verify(storage).setLastLogin(new UserName("foo"), Instant.ofEpochMilli(30000)); - - final LoginToken expected = new LoginToken( - new NewToken(StoredToken.getBuilder( - TokenType.LOGIN, tokenID, new UserName("foo")) - .withLifeTime(Instant.ofEpochMilli(20000), 14 * 24 * 3600 * 1000) - .withContext(TokenCreationContext.getBuilder() - .withNullableAgent("a", "v").build()).build(), - "thisisatoken")); - - assertThat("incorrect login token", lt, is(expected)); - - assertLogEventsCorrect(logEvents, new LogEvent(Level.INFO, - "Logged in user foo with token " + tokenID, Authentication.class)); + for (final MFAStatus mfa: MFAStatus.values()) { + logEvents.clear(); + + final IdentityProvider idp = mock(IdentityProvider.class); + + when(idp.getProviderName()).thenReturn("prov"); + + final TestMocks testauth = initTestMocks(set(idp)); + final AuthStorage storage = testauth.storageMock; + final RandomDataGenerator rand = testauth.randGenMock; + final Clock clock = testauth.clockMock; + final Authentication auth = testauth.auth; + + AuthenticationTester.setConfigUpdateInterval(auth, -1); + + final Map providers = ImmutableMap.of( + "prov", new ProviderConfig(true, false, false)); + + when(storage.getConfig(isA(CollectingExternalConfigMapper.class))) + .thenReturn(new AuthConfigSet( + new AuthConfig(allowLogin, providers, null), + new CollectingExternalConfig(Collections.emptyMap()))); + + final IncomingToken token = new IncomingToken("inctoken"); + + when(storage.getTemporarySessionData(token.getHashedToken())).thenReturn( + TemporarySessionData.create(UUID.randomUUID(), now(), now().plusSeconds(10)) + .login("suporstate", "pkceughherewegoagain")); + + when(idp.getIdentities("foobar", "pkceughherewegoagain", false, null)) + .thenReturn(IdentityProviderResponse.from( + new RemoteIdentity( + new RemoteIdentityID("prov", "id1"), + new RemoteIdentityDetails("user1", "full1", "f@h.com") + ), + mfa + )) + .thenReturn(null); + + final RemoteIdentity storageRemoteID = new RemoteIdentity( + new RemoteIdentityID("prov", "id1"), + new RemoteIdentityDetails("user1", "full1", "f@h.com")); + + final AuthUser user = AuthUser.getBuilder( + new UserName("foo"), UID, new DisplayName("bar"), + Instant.ofEpochMilli(10000L)) + .withRole(userRole) + .withIdentity(storageRemoteID).build(); + + when(storage.getUser(storageRemoteID)).thenReturn(Optional.of(user)).thenReturn(null); + + final UUID tokenID = UUID.randomUUID(); + + when(rand.randomUUID()).thenReturn(tokenID).thenReturn(null); + when(rand.getToken()).thenReturn("thisisatoken").thenReturn(null); + when(clock.instant()).thenReturn(Instant.ofEpochMilli(20000)) + .thenReturn(Instant.ofEpochMilli(30000)).thenReturn(null); + + final LoginToken lt = auth.login( + token, + "prov", + "foobar", + null, + TokenCreationContext.getBuilder().withNullableAgent("a", "v").build(), + "suporstate"); + + verify(storage).deleteTemporarySessionData(token.getHashedToken()); + + verify(storage).storeToken(StoredToken.getBuilder( + TokenType.LOGIN, tokenID, new UserName("foo")) + .withLifeTime(Instant.ofEpochMilli(20000), 14 * 24 * 3600 * 1000) + .withContext(TokenCreationContext.getBuilder() + .withNullableAgent("a", "v").build()) + .withMFA(mfa) + .build(), + "rIWdQ6H23g7MLjLjJTz8k7A6zEbn6+Cnwm5anDwasLc="); + + verify(storage).setLastLogin(new UserName("foo"), Instant.ofEpochMilli(30000)); + + final LoginToken expected = new LoginToken( + new NewToken(StoredToken.getBuilder( + TokenType.LOGIN, tokenID, new UserName("foo")) + .withLifeTime(Instant.ofEpochMilli(20000), 14 * 24 * 3600 * 1000) + .withContext(TokenCreationContext.getBuilder() + .withNullableAgent("a", "v").build()) + .withMFA(mfa) + .build(), + "thisisatoken")); + + assertThat("incorrect login token", lt, is(expected)); + + assertLogEventsCorrect(logEvents, new LogEvent(Level.INFO, + "Logged in user foo with token " + tokenID, Authentication.class)); + } } @Test public void loginContinueStoreSingleIdentity() throws Exception { + // this covers all the paths through the login continue method other than immediate + // login, so we test all MFA types here loginContinueStoreSingleLinkedIdentity(Role.DEV_TOKEN, false, false, false); loginContinueStoreSingleLinkedIdentity(Role.DEV_TOKEN, true, true, false); loginContinueStoreSingleLinkedIdentity(Role.ADMIN, true, false, false); @@ -344,78 +360,85 @@ private void loginContinueStoreSingleLinkedIdentity( final boolean allowLogin, final boolean forceLoginChoice) throws Exception { - logEvents.clear(); - - final IdentityProvider idp = mock(IdentityProvider.class); - - when(idp.getProviderName()).thenReturn("prov"); - - final TestMocks testauth = initTestMocks(set(idp)); - final AuthStorage storage = testauth.storageMock; - final RandomDataGenerator rand = testauth.randGenMock; - final Clock clock = testauth.clockMock; - final Authentication auth = testauth.auth; - - AuthenticationTester.setConfigUpdateInterval(auth, -1); - - final Map providers = ImmutableMap.of( - "prov", new ProviderConfig(true, forceLoginChoice, false)); - - when(storage.getConfig(isA(CollectingExternalConfigMapper.class))) - .thenReturn(new AuthConfigSet( - new AuthConfig(allowLogin, providers, null), - new CollectingExternalConfig(Collections.emptyMap()))); - - final IncomingToken token = new IncomingToken("inctoken"); - - when(storage.getTemporarySessionData(token.getHashedToken())).thenReturn( - TemporarySessionData.create(UUID.randomUUID(), now(), now().plusSeconds(10)) - .login("suporstate2", "pkceisathingiguess")); - - when(idp.getIdentities("foobar", "pkceisathingiguess", false, null)) - .thenReturn(IdentityProviderResponse.from(new RemoteIdentity( - new RemoteIdentityID("prov", "id1"), - new RemoteIdentityDetails("user1", "full1", "f@h.com")))) + for (final MFAStatus mfa: MFAStatus.values()) { + logEvents.clear(); + + final IdentityProvider idp = mock(IdentityProvider.class); + + when(idp.getProviderName()).thenReturn("prov"); + + final TestMocks testauth = initTestMocks(set(idp)); + final AuthStorage storage = testauth.storageMock; + final RandomDataGenerator rand = testauth.randGenMock; + final Clock clock = testauth.clockMock; + final Authentication auth = testauth.auth; + + AuthenticationTester.setConfigUpdateInterval(auth, -1); + + final Map providers = ImmutableMap.of( + "prov", new ProviderConfig(true, forceLoginChoice, false)); + + when(storage.getConfig(isA(CollectingExternalConfigMapper.class))) + .thenReturn(new AuthConfigSet( + new AuthConfig(allowLogin, providers, null), + new CollectingExternalConfig(Collections.emptyMap()))); + + final IncomingToken token = new IncomingToken("inctoken"); + + when(storage.getTemporarySessionData(token.getHashedToken())).thenReturn( + TemporarySessionData.create(UUID.randomUUID(), now(), now().plusSeconds(10)) + .login("suporstate2", "pkceisathingiguess")); + + when(idp.getIdentities("foobar", "pkceisathingiguess", false, null)) + .thenReturn(IdentityProviderResponse.from( + new RemoteIdentity( + new RemoteIdentityID("prov", "id1"), + new RemoteIdentityDetails("user1", "full1", "f@h.com") + ), + mfa + )) + .thenReturn(null); + + final RemoteIdentity storageRemoteID = new RemoteIdentity( + new RemoteIdentityID("prov", "id1"), + new RemoteIdentityDetails("user1", "full1", "f@h.com")); + + final AuthUser.Builder user = AuthUser.getBuilder(new UserName("foo"), UID, + new DisplayName("bar"), Instant.ofEpochMilli(10000L)) + .withRole(userRole) + .withIdentity(storageRemoteID); + if (disabled) { + user.withUserDisabledState(new UserDisabledState( + "d", new UserName("baz"), Instant.ofEpochMilli(5000))); + } + when(storage.getUser(storageRemoteID)).thenReturn(Optional.of(user.build())) + .thenReturn(null); + + final UUID tokenID = UUID.randomUUID(); + + when(rand.randomUUID()).thenReturn(tokenID).thenReturn(null); + when(rand.getToken()).thenReturn("thisisatoken").thenReturn(null); + when(clock.instant()).thenReturn(Instant.ofEpochMilli(20000)) .thenReturn(null); - - final RemoteIdentity storageRemoteID = new RemoteIdentity( - new RemoteIdentityID("prov", "id1"), - new RemoteIdentityDetails("user1", "full1", "f@h.com")); - - final AuthUser.Builder user = AuthUser.getBuilder(new UserName("foo"), UID, - new DisplayName("bar"), Instant.ofEpochMilli(10000L)) - .withRole(userRole) - .withIdentity(storageRemoteID); - if (disabled) { - user.withUserDisabledState(new UserDisabledState( - "d", new UserName("baz"), Instant.ofEpochMilli(5000))); + + final LoginToken lt = auth.login(token, "prov", "foobar", null, CTX, "suporstate2"); + + verify(storage).deleteTemporarySessionData(token.getHashedToken()); + + verify(storage).storeTemporarySessionData(TemporarySessionData + .create(tokenID, Instant.ofEpochMilli(20000), 30 * 60 * 1000) + .login(set(storageRemoteID), mfa), + IncomingToken.hash("thisisatoken")); + + final LoginToken expected = new LoginToken(tempToken( + tokenID, Instant.ofEpochMilli(20000), 30 * 60 * 1000, "thisisatoken")); + + assertThat("incorrect login token", lt, is(expected)); + + assertLogEventsCorrect(logEvents, new LogEvent(Level.INFO, String.format( + "Stored temporary token %s with 1 login identities", tokenID), + Authentication.class)); } - when(storage.getUser(storageRemoteID)).thenReturn(Optional.of(user.build())) - .thenReturn(null); - - final UUID tokenID = UUID.randomUUID(); - - when(rand.randomUUID()).thenReturn(tokenID).thenReturn(null); - when(rand.getToken()).thenReturn("thisisatoken").thenReturn(null); - when(clock.instant()).thenReturn(Instant.ofEpochMilli(20000)) - .thenReturn(null); - - final LoginToken lt = auth.login(token, "prov", "foobar", null, CTX, "suporstate2"); - - verify(storage).deleteTemporarySessionData(token.getHashedToken()); - - verify(storage).storeTemporarySessionData(TemporarySessionData.create( - tokenID, Instant.ofEpochMilli(20000), 30 * 60 * 1000).login(set(storageRemoteID)), - IncomingToken.hash("thisisatoken")); - - final LoginToken expected = new LoginToken(tempToken( - tokenID, Instant.ofEpochMilli(20000), 30 * 60 * 1000, "thisisatoken")); - - assertThat("incorrect login token", lt, is(expected)); - - assertLogEventsCorrect(logEvents, new LogEvent(Level.INFO, String.format( - "Stored temporary token %s with 1 login identities", tokenID), - Authentication.class)); } @Test @@ -471,8 +494,9 @@ public void loginContinueStoreUnlinkedIdentityWithEnvironment() throws Exception verify(storage).deleteTemporarySessionData(token.getHashedToken()); - verify(storage).storeTemporarySessionData(TemporarySessionData.create( - tokenID, Instant.ofEpochMilli(20000), 30 * 60 * 1000).login(set(storageRemoteID)), + verify(storage).storeTemporarySessionData(TemporarySessionData + .create(tokenID, Instant.ofEpochMilli(20000), 30 * 60 * 1000) + .login(set(storageRemoteID), MFAStatus.UNKNOWN), IncomingToken.hash("thisisatoken")); final LoginToken expected = new LoginToken(tempToken( @@ -553,7 +577,7 @@ public void loginContinueStoreLinkedAndUnlinkedIdentity() throws Exception { verify(storage).storeTemporarySessionData(TemporarySessionData.create( tokenID, Instant.ofEpochMilli(20000), 30 * 60 * 1000) - .login(set(storageRemoteID1, storageRemoteID2)), + .login(set(storageRemoteID1, storageRemoteID2), MFAStatus.UNKNOWN), IncomingToken.hash("thisisatoken")); final LoginToken expected = new LoginToken(tempToken( @@ -649,7 +673,10 @@ public void loginContinueStoreMultipleLinkedIdentities() throws Exception { verify(storage).storeTemporarySessionData(TemporarySessionData.create( tokenID, Instant.ofEpochMilli(20000), 30 * 60 * 1000) - .login(set(storageRemoteID1, storageRemoteID2, storageRemoteID3)), + .login( + set(storageRemoteID1, storageRemoteID2, storageRemoteID3), + MFAStatus.UNKNOWN + ), IncomingToken.hash("thisisatoken")); final LoginToken expected = new LoginToken(tempToken( @@ -734,7 +761,10 @@ public void loginContinueStoreMultipleUnLinkedIdentities() throws Exception { verify(storage).storeTemporarySessionData(TemporarySessionData.create( tokenID, Instant.ofEpochMilli(20000), 30 * 60 * 1000) - .login(set(storageRemoteID1, storageRemoteID2, storageRemoteID3)), + .login( + set(storageRemoteID1, storageRemoteID2, storageRemoteID3), + MFAStatus.UNKNOWN + ), IncomingToken.hash("thisisatoken")); final LoginToken expected = new LoginToken(tempToken( @@ -829,7 +859,7 @@ public void loginContinueFailBadTokenOp() throws Exception { final UUID tid = UUID.randomUUID(); when(storage.getTemporarySessionData(token.getHashedToken())).thenReturn( TemporarySessionData.create(tid, Instant.now(), Instant.now()) - .login(set(REMOTE))) + .login(set(REMOTE), MFAStatus.UNKNOWN)) .thenReturn(null); failLoginContinue(auth, token, "ip2", "foo", null, CTX, "state", @@ -1035,8 +1065,13 @@ public void getLoginStateOneUnlinkedID() throws Exception { final UUID id = UUID.randomUUID(); when(storage.getTemporarySessionData(token.getHashedToken())).thenReturn( TemporarySessionData.create(id, SMALL, 10000) - .login(set(new RemoteIdentity(new RemoteIdentityID("prov", "id1"), - new RemoteIdentityDetails("user1", "full1", "f@h.com"))))) + .login( + set(new RemoteIdentity( + new RemoteIdentityID("prov", "id1"), + new RemoteIdentityDetails("user1", "full1", "f@h.com") + )), + MFAStatus.UNKNOWN + )) .thenReturn(null); when(storage.getConfig(isA(CollectingExternalConfigMapper.class))) @@ -1073,13 +1108,21 @@ public void getLoginStateTwoUnlinkedIDsAndNoLoginAllowed() throws Exception { final IncomingToken token = new IncomingToken("foobar"); final UUID id = UUID.randomUUID(); - when(storage.getTemporarySessionData(token.getHashedToken())).thenReturn( - TemporarySessionData.create(id, SMALL, 10000) - .login(set(new RemoteIdentity(new RemoteIdentityID("prov", "id1"), - new RemoteIdentityDetails("user1", "full1", "f@h.com")), - new RemoteIdentity(new RemoteIdentityID("prov", "id2"), - new RemoteIdentityDetails("user2", "full2", "e@g.com"))))) - .thenReturn(null); + final TemporarySessionData tsd = TemporarySessionData.create(id, SMALL, 10000).login( + set( + new RemoteIdentity( + new RemoteIdentityID("prov", "id1"), + new RemoteIdentityDetails("user1", "full1", "f@h.com") + ), + new RemoteIdentity( + new RemoteIdentityID("prov", "id2"), + new RemoteIdentityDetails("user2", "full2", "e@g.com") + ) + ), + MFAStatus.UNKNOWN + ); + when(storage.getTemporarySessionData(token.getHashedToken())) + .thenReturn(tsd).thenReturn(null); when(storage.getConfig(isA(CollectingExternalConfigMapper.class))) .thenReturn(new AuthConfigSet( @@ -1124,8 +1167,13 @@ public void getLoginStateOneLinkedID() throws Exception { when(storage.getTemporarySessionData(token.getHashedToken())).thenReturn( TemporarySessionData.create(id, SMALL, 10000) - .login(set(new RemoteIdentity(new RemoteIdentityID("prov", "id1"), - new RemoteIdentityDetails("user1", "full1", "f@h.com"))))) + .login( + set(new RemoteIdentity( + new RemoteIdentityID("prov", "id1"), + new RemoteIdentityDetails("user1", "full1", "f@h.com") + )), + MFAStatus.UNKNOWN + )) .thenReturn(null); when(storage.getConfig(isA(CollectingExternalConfigMapper.class))) @@ -1170,13 +1218,21 @@ public void getLoginStateTwoLinkedIDs() throws Exception { final IncomingToken token = new IncomingToken("foobar"); final UUID id = UUID.randomUUID(); - when(storage.getTemporarySessionData(token.getHashedToken())).thenReturn( - TemporarySessionData.create(id, SMALL, 10000) - .login(set(new RemoteIdentity(new RemoteIdentityID("prov", "id1"), - new RemoteIdentityDetails("user1", "full1", "f@h.com")), - new RemoteIdentity(new RemoteIdentityID("prov", "id2"), - new RemoteIdentityDetails("user2", "full2", "e@g.com"))))) - .thenReturn(null); + final TemporarySessionData tsd = TemporarySessionData.create(id, SMALL, 10000).login( + set( + new RemoteIdentity( + new RemoteIdentityID("prov", "id1"), + new RemoteIdentityDetails("user1", "full1", "f@h.com") + ), + new RemoteIdentity( + new RemoteIdentityID("prov", "id2"), + new RemoteIdentityDetails("user2", "full2", "e@g.com") + ) + ), + MFAStatus.UNKNOWN + ); + when(storage.getTemporarySessionData(token.getHashedToken())) + .thenReturn(tsd).thenReturn(null); when(storage.getConfig(isA(CollectingExternalConfigMapper.class))) .thenReturn(new AuthConfigSet( @@ -1240,13 +1296,21 @@ public void getLoginStateOneLinkedOneUnlinkedID() throws Exception { final IncomingToken token = new IncomingToken("foobar"); final UUID id = UUID.randomUUID(); - when(storage.getTemporarySessionData(token.getHashedToken())).thenReturn( - TemporarySessionData.create(id, SMALL, 10000) - .login(set(new RemoteIdentity(new RemoteIdentityID("prov", "id1"), - new RemoteIdentityDetails("user1", "full1", "f@h.com")), - new RemoteIdentity(new RemoteIdentityID("prov", "id2"), - new RemoteIdentityDetails("user2", "full2", "e@g.com"))))) - .thenReturn(null); + final TemporarySessionData tsd = TemporarySessionData.create(id, SMALL, 10000).login( + set( + new RemoteIdentity( + new RemoteIdentityID("prov", "id1"), + new RemoteIdentityDetails("user1", "full1", "f@h.com") + ), + new RemoteIdentity( + new RemoteIdentityID("prov", "id2"), + new RemoteIdentityDetails("user2", "full2", "e@g.com") + ) + ), + MFAStatus.UNKNOWN + ); + when(storage.getTemporarySessionData(token.getHashedToken())) + .thenReturn(tsd).thenReturn(null); when(storage.getConfig(isA(CollectingExternalConfigMapper.class))) .thenReturn(new AuthConfigSet( @@ -1384,72 +1448,93 @@ private void failGetLoginState( @Test public void createUser() throws Exception { - final TestMocks testauth = initTestMocks(); - final AuthStorage storage = testauth.storageMock; - final RandomDataGenerator rand = testauth.randGenMock; - final Clock clock = testauth.clockMock; - final Authentication auth = testauth.auth; - - AuthenticationTester.setConfigUpdateInterval(auth, -1); - - final IncomingToken token = new IncomingToken("foobar"); - final UUID tokenID = UUID.randomUUID(); - - when(storage.getConfig(isA(CollectingExternalConfigMapper.class))) - .thenReturn(new AuthConfigSet( - new AuthConfig(true, null, null), - new CollectingExternalConfig(Collections.emptyMap()))); - - when(storage.getTemporarySessionData(token.getHashedToken())).thenReturn( - TemporarySessionData.create(UUID.randomUUID(), SMALL, 10000) - .login(set(new RemoteIdentity(new RemoteIdentityID("prov", "id1"), - new RemoteIdentityDetails("user1", "full1", "f@h.com")), - new RemoteIdentity(new RemoteIdentityID("prov", "id2"), - new RemoteIdentityDetails("user2", "full2", "e@g.com"))))) - .thenReturn(null); - - when(clock.instant()).thenReturn(Instant.ofEpochMilli(10000L), - Instant.ofEpochMilli(20000L), Instant.ofEpochMilli(30000L), null); - when(rand.randomUUID()).thenReturn(UID).thenReturn(tokenID).thenReturn(null); - when(rand.getToken()).thenReturn("mfingtoken"); - - final NewToken nt = auth.createUser(token, "ef0518c79af70ed979907969c6d0a0f7", - new NewUserName("foo"), new DisplayName("bar"), new EmailAddress("f@h.com"), - set(new PolicyID("pid1"), new PolicyID("pid2")), - TokenCreationContext.getBuilder().withNullableDevice("d").build(), false); - - verify(storage).createUser(NewUser.getBuilder( - new NewUserName("foo"), UID, new DisplayName("bar"), Instant.ofEpochMilli(10000), - new RemoteIdentity(new RemoteIdentityID("prov", "id1"), - new RemoteIdentityDetails("user1", "full1", "f@h.com"))) - .withEmailAddress(new EmailAddress("f@h.com")) - .withPolicyID(new PolicyID("pid1"), Instant.ofEpochMilli(10000)) - .withPolicyID(new PolicyID("pid2"), Instant.ofEpochMilli(10000)).build()); - - verify(storage, never()).link(any(), any()); - - verify(storage).storeToken(StoredToken.getBuilder( - TokenType.LOGIN, tokenID, new NewUserName("foo")) - .withLifeTime(Instant.ofEpochMilli(20000), 14 * 24 * 3600 * 1000) - .withContext(TokenCreationContext.getBuilder().withNullableDevice("d").build()) - .build(), - "hQ9Z3p0WaYunsmIBRUcJgBn5Pd4BCYhOEQCE3enFOzA="); - - verify(storage).setLastLogin(new NewUserName("foo"), Instant.ofEpochMilli(30000)); - verify(storage).deleteTemporarySessionData(token.getHashedToken()); - - assertThat("incorrect new token", nt, is(new NewToken(StoredToken.getBuilder( - TokenType.LOGIN, tokenID, new NewUserName("foo")) - .withLifeTime(Instant.ofEpochMilli(20000), 14 * 24 * 3600 * 1000) - .withContext(TokenCreationContext.getBuilder().withNullableDevice("d").build()) - .build(), - "mfingtoken"))); - - assertLogEventsCorrect(logEvents, new LogEvent(Level.INFO, - "Created user foo linked to remote identity " + - "ef0518c79af70ed979907969c6d0a0f7 prov id1 user1", Authentication.class), - new LogEvent(Level.INFO, "Logged in user foo with token " + tokenID, - Authentication.class)); + // There's only one happy path through createUser wrt MFA so we just test here + for (final MFAStatus mfa: MFAStatus.values()) { + logEvents.clear(); + final TestMocks testauth = initTestMocks(); + final AuthStorage storage = testauth.storageMock; + final RandomDataGenerator rand = testauth.randGenMock; + final Clock clock = testauth.clockMock; + final Authentication auth = testauth.auth; + + AuthenticationTester.setConfigUpdateInterval(auth, -1); + + final IncomingToken token = new IncomingToken("foobar"); + final UUID tokenID = UUID.randomUUID(); + + when(storage.getConfig(isA(CollectingExternalConfigMapper.class))) + .thenReturn(new AuthConfigSet( + new AuthConfig(true, null, null), + new CollectingExternalConfig(Collections.emptyMap()))); + + final TemporarySessionData tsd = TemporarySessionData.create( + UUID.randomUUID(), SMALL, 10000) + .login( + set( + new RemoteIdentity( + new RemoteIdentityID("prov", "id1"), + new RemoteIdentityDetails("user1", "full1", "f@h.com") + ), + new RemoteIdentity( + new RemoteIdentityID("prov", "id2"), + new RemoteIdentityDetails("user2", "full2", "e@g.com") + ) + ), + mfa + ); + when(storage.getTemporarySessionData(token.getHashedToken())) + .thenReturn(tsd).thenReturn(null); + + when(clock.instant()).thenReturn(Instant.ofEpochMilli(10000L), + Instant.ofEpochMilli(20000L), Instant.ofEpochMilli(30000L), null); + when(rand.randomUUID()).thenReturn(UID).thenReturn(tokenID).thenReturn(null); + when(rand.getToken()).thenReturn("mfingtoken"); + + final NewToken nt = auth.createUser(token, "ef0518c79af70ed979907969c6d0a0f7", + new NewUserName("foo"), new DisplayName("bar"), new EmailAddress("f@h.com"), + set(new PolicyID("pid1"), new PolicyID("pid2")), + TokenCreationContext.getBuilder().withNullableDevice("d").build(), false); + + verify(storage).createUser(NewUser.getBuilder( + new NewUserName("foo"), + UID, + new DisplayName("bar"), + Instant.ofEpochMilli(10000), + new RemoteIdentity(new RemoteIdentityID("prov", "id1"), + new RemoteIdentityDetails("user1", "full1", "f@h.com") + ) + ) + .withEmailAddress(new EmailAddress("f@h.com")) + .withPolicyID(new PolicyID("pid1"), Instant.ofEpochMilli(10000)) + .withPolicyID(new PolicyID("pid2"), Instant.ofEpochMilli(10000)).build()); + + verify(storage, never()).link(any(), any()); + + verify(storage).storeToken(StoredToken.getBuilder( + TokenType.LOGIN, tokenID, new NewUserName("foo")) + .withLifeTime(Instant.ofEpochMilli(20000), 14 * 24 * 3600 * 1000) + .withContext(TokenCreationContext.getBuilder().withNullableDevice("d").build()) + .withMFA(mfa) + .build(), + "hQ9Z3p0WaYunsmIBRUcJgBn5Pd4BCYhOEQCE3enFOzA="); + + verify(storage).setLastLogin(new NewUserName("foo"), Instant.ofEpochMilli(30000)); + verify(storage).deleteTemporarySessionData(token.getHashedToken()); + + assertThat("incorrect new token", nt, is(new NewToken(StoredToken.getBuilder( + TokenType.LOGIN, tokenID, new NewUserName("foo")) + .withLifeTime(Instant.ofEpochMilli(20000), 14 * 24 * 3600 * 1000) + .withContext(TokenCreationContext.getBuilder().withNullableDevice("d").build()) + .withMFA(mfa) + .build(), + "mfingtoken"))); + + assertLogEventsCorrect(logEvents, new LogEvent(Level.INFO, + "Created user foo linked to remote identity " + + "ef0518c79af70ed979907969c6d0a0f7 prov id1 user1", Authentication.class), + new LogEvent(Level.INFO, "Logged in user foo with token " + tokenID, + Authentication.class)); + } } @Test @@ -1473,10 +1558,14 @@ public void createUserAlternateTokenLifeTimeAndEmptyLinks() throws Exception { new CollectingExternalConfig(Collections.emptyMap()))); when(storage.getTemporarySessionData(token.getHashedToken())).thenReturn( - TemporarySessionData.create(UUID.randomUUID(), SMALL, 10000) - .login(set(new RemoteIdentity(new RemoteIdentityID("prov", "id1"), - new RemoteIdentityDetails("user1", "full1", "f@h.com"))))) - .thenReturn(null); + TemporarySessionData.create(UUID.randomUUID(), SMALL, 10000).login( + set(new RemoteIdentity( + new RemoteIdentityID("prov", "id1"), + new RemoteIdentityDetails("user1", "full1", "f@h.com") + )), + MFAStatus.UNKNOWN + ) + ).thenReturn(null); when(clock.instant()).thenReturn(Instant.ofEpochMilli(10000L), Instant.ofEpochMilli(20000L), Instant.ofEpochMilli(30000L), null); @@ -1546,19 +1635,34 @@ public void createUserAndLinkAll() throws Exception { new AuthConfig(true, null, null), new CollectingExternalConfig(Collections.emptyMap()))); - when(storage.getTemporarySessionData(token.getHashedToken())).thenReturn( - TemporarySessionData.create(UUID.randomUUID(), SMALL, 10000) - .login(set(new RemoteIdentity(new RemoteIdentityID("prov", "id1"), - new RemoteIdentityDetails("user1", "full1", "f@h.com")), - new RemoteIdentity(new RemoteIdentityID("prov", "id2"), - new RemoteIdentityDetails("user2", "full2", "e@g.com")), - new RemoteIdentity(new RemoteIdentityID("prov", "id3"), - new RemoteIdentityDetails("user3", "full3", "d@g.com")), - new RemoteIdentity(new RemoteIdentityID("prov", "id4"), - new RemoteIdentityDetails("user4", "full4", "c@g.com")), - new RemoteIdentity(new RemoteIdentityID("prov", "id5"), - new RemoteIdentityDetails("user5", "full5", "b@g.com"))))) - .thenReturn(null); + TemporarySessionData tsd = TemporarySessionData.create(UUID.randomUUID(), SMALL, 10000) + .login( + set( + new RemoteIdentity( + new RemoteIdentityID("prov", "id1"), + new RemoteIdentityDetails("user1", "full1", "f@h.com") + ), + new RemoteIdentity( + new RemoteIdentityID("prov", "id2"), + new RemoteIdentityDetails("user2", "full2", "e@g.com") + ), + new RemoteIdentity( + new RemoteIdentityID("prov", "id3"), + new RemoteIdentityDetails("user3", "full3", "d@g.com") + ), + new RemoteIdentity( + new RemoteIdentityID("prov", "id4"), + new RemoteIdentityDetails("user4", "full4", "c@g.com") + ), + new RemoteIdentity( + new RemoteIdentityID("prov", "id5"), + new RemoteIdentityDetails("user5", "full5", "b@g.com") + ) + ), + MFAStatus.UNKNOWN + ); + when(storage.getTemporarySessionData(token.getHashedToken())) + .thenReturn(tsd).thenReturn(null); when(storage.getUser(new RemoteIdentity(new RemoteIdentityID("prov", "id2"), new RemoteIdentityDetails("user2", "full2", "e@g.com")))) @@ -1662,7 +1766,7 @@ public void createUserFailNullsAndEmpties() throws Exception { when(storage.getTemporarySessionData(t.getHashedToken())).thenReturn( TemporarySessionData.create(UUID.randomUUID(), SMALL, SMALL) - .login(set(REMOTE))); + .login(set(REMOTE), MFAStatus.UNKNOWN)); final String id = "bar"; final NewUserName u = new NewUserName("baz"); @@ -1873,8 +1977,14 @@ public void createUserFailNoMatchingIdentities() throws Exception { when(storage.getTemporarySessionData(t.getHashedToken())).thenReturn( TemporarySessionData.create(UUID.randomUUID(), SMALL, 10000) - .login(set(new RemoteIdentity(new RemoteIdentityID("prov", "id1"), - new RemoteIdentityDetails("user1", "full1", "f@h.com"))))) + .login( + set(new RemoteIdentity( + new RemoteIdentityID("prov", "id1"), + new RemoteIdentityDetails("user1", "full1", "f@h.com") + )), + MFAStatus.UNKNOWN + ) + ) .thenReturn(null); final String id = "bar"; //yep, that won't match @@ -1906,9 +2016,15 @@ public void createUserFailUserExists() throws Exception { final IncomingToken t = new IncomingToken("foo"); when(storage.getTemporarySessionData(t.getHashedToken())).thenReturn( - TemporarySessionData.create(UUID.randomUUID(), SMALL, 10000) - .login(set(new RemoteIdentity(new RemoteIdentityID("prov", "id1"), - new RemoteIdentityDetails("user1", "full1", "f@h.com"))))) + TemporarySessionData.create(UUID.randomUUID(), SMALL, 10000).login( + set( + new RemoteIdentity( + new RemoteIdentityID("prov", "id1"), + new RemoteIdentityDetails("user1", "full1", "f@h.com") + ) + ), + MFAStatus.UNKNOWN + )) .thenReturn(null); when(testauth.randGenMock.randomUUID()).thenReturn(UID).thenReturn(null); @@ -1948,9 +2064,15 @@ public void createUserFailIdentityLinked() throws Exception { final IncomingToken t = new IncomingToken("foo"); when(storage.getTemporarySessionData(t.getHashedToken())).thenReturn( - TemporarySessionData.create(UUID.randomUUID(), SMALL, 10000) - .login(set(new RemoteIdentity(new RemoteIdentityID("prov", "id1"), - new RemoteIdentityDetails("user1", "full1", "f@h.com"))))) + TemporarySessionData.create(UUID.randomUUID(), SMALL, 10000).login( + set( + new RemoteIdentity( + new RemoteIdentityID("prov", "id1"), + new RemoteIdentityDetails("user1", "full1", "f@h.com") + ) + ), + MFAStatus.UNKNOWN + )) .thenReturn(null); when(testauth.randGenMock.randomUUID()).thenReturn(UID).thenReturn(null); @@ -1992,9 +2114,15 @@ public void createUserFailNoRole() throws Exception { final IncomingToken t = new IncomingToken("foo"); when(storage.getTemporarySessionData(t.getHashedToken())).thenReturn( - TemporarySessionData.create(UUID.randomUUID(), SMALL, 10000) - .login(set(new RemoteIdentity(new RemoteIdentityID("prov", "id1"), - new RemoteIdentityDetails("user1", "full1", "f@h.com"))))) + TemporarySessionData.create(UUID.randomUUID(), SMALL, 10000).login( + set( + new RemoteIdentity( + new RemoteIdentityID("prov", "id1"), + new RemoteIdentityDetails("user1", "full1", "f@h.com") + ) + ), + MFAStatus.UNKNOWN + )) .thenReturn(null); when(testauth.randGenMock.randomUUID()).thenReturn(UID).thenReturn(null); @@ -2035,11 +2163,19 @@ public void createUserFailLinkAllNoSuchUser() throws Exception { final IncomingToken t = new IncomingToken("foo"); when(storage.getTemporarySessionData(t.getHashedToken())).thenReturn( - TemporarySessionData.create(UUID.randomUUID(), SMALL, 10000) - .login(set(new RemoteIdentity(new RemoteIdentityID("prov", "id1"), - new RemoteIdentityDetails("user1", "full1", "f@h.com")), - new RemoteIdentity(new RemoteIdentityID("prov", "id2"), - new RemoteIdentityDetails("user2", "full2", "e@g.com"))))) + TemporarySessionData.create(UUID.randomUUID(), SMALL, 10000).login( + set( + new RemoteIdentity( + new RemoteIdentityID("prov", "id1"), + new RemoteIdentityDetails("user1", "full1", "f@h.com") + ), + new RemoteIdentity( + new RemoteIdentityID("prov", "id2"), + new RemoteIdentityDetails("user2", "full2", "e@g.com") + ) + ), + MFAStatus.UNKNOWN + )) .thenReturn(null); when(testauth.randGenMock.randomUUID()).thenReturn(UID).thenReturn(null); @@ -2085,11 +2221,19 @@ public void createUserFailLinkFailed() throws Exception { final IncomingToken t = new IncomingToken("foo"); when(storage.getTemporarySessionData(t.getHashedToken())).thenReturn( - TemporarySessionData.create(UUID.randomUUID(), SMALL, 10000) - .login(set(new RemoteIdentity(new RemoteIdentityID("prov", "id1"), - new RemoteIdentityDetails("user1", "full1", "f@h.com")), - new RemoteIdentity(new RemoteIdentityID("prov", "id2"), - new RemoteIdentityDetails("user2", "full2", "e@g.com"))))) + TemporarySessionData.create(UUID.randomUUID(), SMALL, 10000).login( + set( + new RemoteIdentity( + new RemoteIdentityID("prov", "id1"), + new RemoteIdentityDetails("user1", "full1", "f@h.com") + ), + new RemoteIdentity( + new RemoteIdentityID("prov", "id2"), + new RemoteIdentityDetails("user2", "full2", "e@g.com") + ) + ), + MFAStatus.UNKNOWN + )) .thenReturn(null); when(testauth.randGenMock.randomUUID()).thenReturn(UID).thenReturn(null); @@ -2138,11 +2282,19 @@ public void createUserFailNoSuchUserOnSetLastLogin() throws Exception { new CollectingExternalConfig(Collections.emptyMap()))); when(storage.getTemporarySessionData(token.getHashedToken())).thenReturn( - TemporarySessionData.create(UUID.randomUUID(), SMALL, 10000) - .login(set(new RemoteIdentity(new RemoteIdentityID("prov", "id1"), - new RemoteIdentityDetails("user1", "full1", "f@h.com")), - new RemoteIdentity(new RemoteIdentityID("prov", "id2"), - new RemoteIdentityDetails("user2", "full2", "e@g.com"))))) + TemporarySessionData.create(UUID.randomUUID(), SMALL, 10000).login( + set( + new RemoteIdentity( + new RemoteIdentityID("prov", "id1"), + new RemoteIdentityDetails("user1", "full1", "f@h.com") + ), + new RemoteIdentity( + new RemoteIdentityID("prov", "id2"), + new RemoteIdentityDetails("user2", "full2", "e@g.com") + ) + ), + MFAStatus.UNKNOWN + )) .thenReturn(null); when(clock.instant()).thenReturn(Instant.ofEpochMilli(10000L), @@ -2181,81 +2333,100 @@ private void failCreateUser( @Test public void completeLogin() throws Exception { + // There's only one happy path through the final login method wrt MFA so we just test here completeLogin(Role.DEV_TOKEN, true); completeLogin(Role.ADMIN, false); completeLogin(Role.CREATE_ADMIN, false); } - private void completeLogin(final Role userRole, final boolean allowLogin) - throws Exception { - logEvents.clear(); - - final TestMocks testauth = initTestMocks(); - final AuthStorage storage = testauth.storageMock; - final RandomDataGenerator rand = testauth.randGenMock; - final Clock clock = testauth.clockMock; - final Authentication auth = testauth.auth; - - AuthenticationTester.setConfigUpdateInterval(auth, -1); - - final IncomingToken token = new IncomingToken("foobar"); - final UUID tokenID = UUID.randomUUID(); - - when(storage.getTemporarySessionData(token.getHashedToken())).thenReturn( - TemporarySessionData.create(UUID.randomUUID(), SMALL, 10000) - .login(set(new RemoteIdentity(new RemoteIdentityID("prov", "id1"), - new RemoteIdentityDetails("user1", "full1", "f@h.com")), - new RemoteIdentity(new RemoteIdentityID("prov", "id2"), - new RemoteIdentityDetails("user2", "full2", "e@g.com"))))) - .thenReturn(null); - - when(storage.getUser(new RemoteIdentity(new RemoteIdentityID("prov", "id1"), - new RemoteIdentityDetails("user1", "full1", "f@h.com")))).thenReturn(Optional.of( - AuthUser.getBuilder(new UserName("foo"), UID, new DisplayName("bar"), - Instant.ofEpochMilli(70000)) - .withRole(userRole) - .withIdentity(new RemoteIdentity(new RemoteIdentityID("prov", "id1"), - new RemoteIdentityDetails("user1", "full1", "f@h.com"))) - .build())); - - when(storage.getConfig(isA(CollectingExternalConfigMapper.class))) - .thenReturn(new AuthConfigSet( - new AuthConfig(allowLogin, null, null), - new CollectingExternalConfig(Collections.emptyMap()))); - - when(clock.instant()).thenReturn(Instant.ofEpochMilli(10000L), - Instant.ofEpochMilli(20000L), null); - when(rand.randomUUID()).thenReturn(tokenID).thenReturn(null); - when(rand.getToken()).thenReturn("mfingtoken"); - - final NewToken nt = auth.login(token, "ef0518c79af70ed979907969c6d0a0f7", - set(new PolicyID("pid1"), new PolicyID("pid2")), - TokenCreationContext.getBuilder().withNullableDevice("dev").build(), false); - - verify(storage).addPolicyIDs(new UserName("foo"), - set(new PolicyID("pid1"), new PolicyID("pid2"))); - - verify(storage, never()).link(any(), any()); - - verify(storage).storeToken(StoredToken.getBuilder( - TokenType.LOGIN, tokenID, new UserName("foo")) - .withLifeTime(Instant.ofEpochMilli(10000), 14 * 24 * 3600 * 1000) - .withContext(TokenCreationContext.getBuilder().withNullableDevice("dev").build()) - .build(), - "hQ9Z3p0WaYunsmIBRUcJgBn5Pd4BCYhOEQCE3enFOzA="); - - verify(storage).setLastLogin(new UserName("foo"), Instant.ofEpochMilli(20000)); - verify(storage).deleteTemporarySessionData(token.getHashedToken()); - - assertThat("incorrect new token", nt, is(new NewToken(StoredToken.getBuilder( - TokenType.LOGIN, tokenID, new UserName("foo")) - .withLifeTime(Instant.ofEpochMilli(10000), 14 * 24 * 3600 * 1000) - .withContext(TokenCreationContext.getBuilder().withNullableDevice("dev").build()) - .build(), - "mfingtoken"))); - - assertLogEventsCorrect(logEvents, new LogEvent(Level.INFO, - "Logged in user foo with token " + tokenID, Authentication.class)); + private void completeLogin(final Role userRole, final boolean allowLogin) throws Exception { + for (final MFAStatus mfa: MFAStatus.values()) { + logEvents.clear(); + + final TestMocks testauth = initTestMocks(); + final AuthStorage storage = testauth.storageMock; + final RandomDataGenerator rand = testauth.randGenMock; + final Clock clock = testauth.clockMock; + final Authentication auth = testauth.auth; + + AuthenticationTester.setConfigUpdateInterval(auth, -1); + + final IncomingToken token = new IncomingToken("foobar"); + final UUID tokenID = UUID.randomUUID(); + + when(storage.getTemporarySessionData(token.getHashedToken())).thenReturn( + TemporarySessionData.create(UUID.randomUUID(), SMALL, 10000).login( + set( + new RemoteIdentity( + new RemoteIdentityID("prov", "id1"), + new RemoteIdentityDetails("user1", "full1", "f@h.com") + ), + new RemoteIdentity( + new RemoteIdentityID("prov", "id2"), + new RemoteIdentityDetails("user2", "full2", "e@g.com") + ) + ), + mfa + )) + .thenReturn(null); + + when(storage.getUser( + new RemoteIdentity( + new RemoteIdentityID("prov", "id1"), + new RemoteIdentityDetails("user1", "full1", "f@h.com") + ) + )).thenReturn(Optional.of( + AuthUser.getBuilder(new UserName("foo"), UID, new DisplayName("bar"), + Instant.ofEpochMilli(70000)) + .withRole(userRole) + .withIdentity(new RemoteIdentity(new RemoteIdentityID("prov", "id1"), + new RemoteIdentityDetails("user1", "full1", "f@h.com"))) + .build() + )); + + when(storage.getConfig(isA(CollectingExternalConfigMapper.class))) + .thenReturn(new AuthConfigSet( + new AuthConfig(allowLogin, null, null), + new CollectingExternalConfig(Collections.emptyMap()))); + + when(clock.instant()).thenReturn(Instant.ofEpochMilli(10000L), + Instant.ofEpochMilli(20000L), null); + when(rand.randomUUID()).thenReturn(tokenID).thenReturn(null); + when(rand.getToken()).thenReturn("mfingtoken"); + + final NewToken nt = auth.login(token, "ef0518c79af70ed979907969c6d0a0f7", + set(new PolicyID("pid1"), new PolicyID("pid2")), + TokenCreationContext.getBuilder().withNullableDevice("dev").build(), false); + + verify(storage).addPolicyIDs(new UserName("foo"), + set(new PolicyID("pid1"), new PolicyID("pid2"))); + + verify(storage, never()).link(any(), any()); + + verify(storage).storeToken(StoredToken.getBuilder( + TokenType.LOGIN, tokenID, new UserName("foo")) + .withLifeTime(Instant.ofEpochMilli(10000), 14 * 24 * 3600 * 1000) + .withContext(TokenCreationContext.getBuilder().withNullableDevice("dev") + .build()) + .withMFA(mfa) + .build(), + "hQ9Z3p0WaYunsmIBRUcJgBn5Pd4BCYhOEQCE3enFOzA="); + + verify(storage).setLastLogin(new UserName("foo"), Instant.ofEpochMilli(20000)); + verify(storage).deleteTemporarySessionData(token.getHashedToken()); + + assertThat("incorrect new token", nt, is(new NewToken(StoredToken.getBuilder( + TokenType.LOGIN, tokenID, new UserName("foo")) + .withLifeTime(Instant.ofEpochMilli(10000), 14 * 24 * 3600 * 1000) + .withContext(TokenCreationContext.getBuilder().withNullableDevice("dev") + .build()) + .withMFA(mfa) + .build(), + "mfingtoken"))); + + assertLogEventsCorrect(logEvents, new LogEvent(Level.INFO, + "Logged in user foo with token " + tokenID, Authentication.class)); + } } @Test @@ -2273,9 +2444,15 @@ public void completeLoginWithAlternateTokenLifetimeAndEmptyLinks() throws Except final UUID tokenID = UUID.randomUUID(); when(storage.getTemporarySessionData(token.getHashedToken())).thenReturn( - TemporarySessionData.create(UUID.randomUUID(), SMALL, 10000) - .login(set(new RemoteIdentity(new RemoteIdentityID("prov", "id1"), - new RemoteIdentityDetails("user1", "full1", "f@h.com"))))) + TemporarySessionData.create(UUID.randomUUID(), SMALL, 10000).login( + set( + new RemoteIdentity( + new RemoteIdentityID("prov", "id1"), + new RemoteIdentityDetails("user1", "full1", "f@h.com") + ) + ), + MFAStatus.UNKNOWN + )) .thenReturn(null); when(storage.getUser(new RemoteIdentity(new RemoteIdentityID("prov", "id1"), @@ -2346,19 +2523,34 @@ public void completeLoginAndLinkAll() throws Exception { final IncomingToken token = new IncomingToken("foobar"); final UUID tokenID = UUID.randomUUID(); - when(storage.getTemporarySessionData(token.getHashedToken())).thenReturn( - TemporarySessionData.create(UUID.randomUUID(), SMALL, 10000) - .login(set(new RemoteIdentity(new RemoteIdentityID("prov", "id1"), - new RemoteIdentityDetails("user1", "full1", "f@h.com")), - new RemoteIdentity(new RemoteIdentityID("prov", "id2"), - new RemoteIdentityDetails("user2", "full2", "e@g.com")), - new RemoteIdentity(new RemoteIdentityID("prov", "id3"), - new RemoteIdentityDetails("user3", "full3", "d@g.com")), - new RemoteIdentity(new RemoteIdentityID("prov", "id4"), - new RemoteIdentityDetails("user4", "full4", "c@g.com")), - new RemoteIdentity(new RemoteIdentityID("prov", "id5"), - new RemoteIdentityDetails("user5", "full5", "b@g.com"))))) - .thenReturn(null); + TemporarySessionData tsd = TemporarySessionData.create(UUID.randomUUID(), SMALL, 10000) + .login( + set( + new RemoteIdentity( + new RemoteIdentityID("prov", "id1"), + new RemoteIdentityDetails("user1", "full1", "f@h.com") + ), + new RemoteIdentity( + new RemoteIdentityID("prov", "id2"), + new RemoteIdentityDetails("user2", "full2", "e@g.com") + ), + new RemoteIdentity( + new RemoteIdentityID("prov", "id3"), + new RemoteIdentityDetails("user3", "full3", "d@g.com") + ), + new RemoteIdentity( + new RemoteIdentityID("prov", "id4"), + new RemoteIdentityDetails("user4", "full4", "c@g.com") + ), + new RemoteIdentity( + new RemoteIdentityID("prov", "id5"), + new RemoteIdentityDetails("user5", "full5", "b@g.com") + ) + ), + MFAStatus.UNKNOWN + ); + when(storage.getTemporarySessionData(token.getHashedToken())) + .thenReturn(tsd).thenReturn(null); when(storage.getUser(new RemoteIdentity(new RemoteIdentityID("prov", "id1"), new RemoteIdentityDetails("user1", "full1", "f@h.com")))).thenReturn(Optional.of( @@ -2466,7 +2658,7 @@ public void completeLoginFailNullsAndEmpties() throws Exception { when(storage.getTemporarySessionData(t.getHashedToken())).thenReturn( TemporarySessionData.create(UUID.randomUUID(), SMALL, SMALL) - .login(set(REMOTE))); + .login(set(REMOTE), MFAStatus.UNKNOWN)); failCompleteLogin(auth, null, id, pids, CTX, l, new NullPointerException("Temporary token")); @@ -2574,9 +2766,15 @@ public void completeLoginFailBadId() throws Exception { final boolean l = false; when(storage.getTemporarySessionData(t.getHashedToken())).thenReturn( - TemporarySessionData.create(UUID.randomUUID(), SMALL, 10000) - .login(set(new RemoteIdentity(new RemoteIdentityID("prov", "id1"), - new RemoteIdentityDetails("user1", "full1", "f@h.com"))))) + TemporarySessionData.create(UUID.randomUUID(), SMALL, 10000).login( + set( + new RemoteIdentity( + new RemoteIdentityID("prov", "id1"), + new RemoteIdentityDetails("user1", "full1", "f@h.com") + ) + ), + MFAStatus.UNKNOWN + )) .thenReturn(null); failCompleteLogin(auth, t, id, pids, CTX, l, @@ -2596,9 +2794,15 @@ public void completeLoginFailNoUser() throws Exception { final boolean l = false; when(storage.getTemporarySessionData(t.getHashedToken())).thenReturn( - TemporarySessionData.create(UUID.randomUUID(), SMALL, 10000) - .login(set(new RemoteIdentity(new RemoteIdentityID("prov", "id1"), - new RemoteIdentityDetails("user1", "full1", "f@h.com"))))) + TemporarySessionData.create(UUID.randomUUID(), SMALL, 10000).login( + set( + new RemoteIdentity( + new RemoteIdentityID("prov", "id1"), + new RemoteIdentityDetails("user1", "full1", "f@h.com") + ) + ), + MFAStatus.UNKNOWN + )) .thenReturn(null); when(storage.getUser(new RemoteIdentity(new RemoteIdentityID("prov", "id1"), @@ -2622,9 +2826,15 @@ public void completeLoginFailLoginDisabled() throws Exception { final boolean l = false; when(storage.getTemporarySessionData(t.getHashedToken())).thenReturn( - TemporarySessionData.create(UUID.randomUUID(), SMALL, 10000) - .login(set(new RemoteIdentity(new RemoteIdentityID("prov", "id1"), - new RemoteIdentityDetails("user1", "full1", "f@h.com"))))) + TemporarySessionData.create(UUID.randomUUID(), SMALL, 10000).login( + set( + new RemoteIdentity( + new RemoteIdentityID("prov", "id1"), + new RemoteIdentityDetails("user1", "full1", "f@h.com") + ) + ), + MFAStatus.UNKNOWN + )) .thenReturn(null); when(storage.getUser(new RemoteIdentity(new RemoteIdentityID("prov", "id1"), @@ -2658,9 +2868,15 @@ public void completeLoginFailDisabledAccount() throws Exception { final boolean l = false; when(storage.getTemporarySessionData(t.getHashedToken())).thenReturn( - TemporarySessionData.create(UUID.randomUUID(), SMALL, 10000) - .login(set(new RemoteIdentity(new RemoteIdentityID("prov", "id1"), - new RemoteIdentityDetails("user1", "full1", "f@h.com"))))) + TemporarySessionData.create(UUID.randomUUID(), SMALL, 10000).login( + set( + new RemoteIdentity( + new RemoteIdentityID("prov", "id1"), + new RemoteIdentityDetails("user1", "full1", "f@h.com") + ) + ), + MFAStatus.UNKNOWN + )) .thenReturn(null); when(storage.getUser(new RemoteIdentity(new RemoteIdentityID("prov", "id1"), @@ -2696,9 +2912,15 @@ public void completeLoginFailNoSuchUserOnPolicyID() throws Exception { final boolean l = false; when(storage.getTemporarySessionData(t.getHashedToken())).thenReturn( - TemporarySessionData.create(UUID.randomUUID(), SMALL, 10000) - .login(set(new RemoteIdentity(new RemoteIdentityID("prov", "id1"), - new RemoteIdentityDetails("user1", "full1", "f@h.com"))))) + TemporarySessionData.create(UUID.randomUUID(), SMALL, 10000).login( + set( + new RemoteIdentity( + new RemoteIdentityID("prov", "id1"), + new RemoteIdentityDetails("user1", "full1", "f@h.com") + ) + ), + MFAStatus.UNKNOWN + )) .thenReturn(null); when(storage.getUser(new RemoteIdentity(new RemoteIdentityID("prov", "id1"), @@ -2736,11 +2958,19 @@ public void completeLoginFailNoSuchUserOnLink() throws Exception { final boolean l = true; when(storage.getTemporarySessionData(t.getHashedToken())).thenReturn( - TemporarySessionData.create(UUID.randomUUID(), SMALL, 10000) - .login(set(new RemoteIdentity(new RemoteIdentityID("prov", "id1"), - new RemoteIdentityDetails("user1", "full1", "f@h.com")), - new RemoteIdentity(new RemoteIdentityID("prov", "id2"), - new RemoteIdentityDetails("user2", "full2", "e@g.com"))))) + TemporarySessionData.create(UUID.randomUUID(), SMALL, 10000).login( + set( + new RemoteIdentity( + new RemoteIdentityID("prov", "id1"), + new RemoteIdentityDetails("user1", "full1", "f@h.com") + ), + new RemoteIdentity( + new RemoteIdentityID("prov", "id2"), + new RemoteIdentityDetails("user2", "full2", "e@g.com") + ) + ), + MFAStatus.UNKNOWN + )) .thenReturn(null); when(storage.getUser(new RemoteIdentity(new RemoteIdentityID("prov", "id1"), @@ -2782,11 +3012,19 @@ public void completeLoginFailLinkFailOnLink() throws Exception { final boolean l = true; when(storage.getTemporarySessionData(t.getHashedToken())).thenReturn( - TemporarySessionData.create(UUID.randomUUID(), SMALL, 10000) - .login(set(new RemoteIdentity(new RemoteIdentityID("prov", "id1"), - new RemoteIdentityDetails("user1", "full1", "f@h.com")), - new RemoteIdentity(new RemoteIdentityID("prov", "id2"), - new RemoteIdentityDetails("user2", "full2", "e@g.com"))))) + TemporarySessionData.create(UUID.randomUUID(), SMALL, 10000).login( + set( + new RemoteIdentity( + new RemoteIdentityID("prov", "id1"), + new RemoteIdentityDetails("user1", "full1", "f@h.com") + ), + new RemoteIdentity( + new RemoteIdentityID("prov", "id2"), + new RemoteIdentityDetails("user2", "full2", "e@g.com") + ) + ), + MFAStatus.UNKNOWN + )) .thenReturn(null); when(storage.getUser(new RemoteIdentity(new RemoteIdentityID("prov", "id1"), @@ -2830,9 +3068,15 @@ public void completeLoginFailNoSuchUserOnSetLastLogin() throws Exception { final boolean l = false; when(storage.getTemporarySessionData(t.getHashedToken())).thenReturn( - TemporarySessionData.create(UUID.randomUUID(), SMALL, 10000) - .login(set(new RemoteIdentity(new RemoteIdentityID("prov", "id1"), - new RemoteIdentityDetails("user1", "full1", "f@h.com"))))) + TemporarySessionData.create(UUID.randomUUID(), SMALL, 10000).login( + set( + new RemoteIdentity( + new RemoteIdentityID("prov", "id1"), + new RemoteIdentityDetails("user1", "full1", "f@h.com") + ) + ), + MFAStatus.UNKNOWN + )) .thenReturn(null); when(storage.getUser(new RemoteIdentity(new RemoteIdentityID("prov", "id1"), diff --git a/src/test/java/us/kbase/test/auth2/lib/TemporarySessionDataTest.java b/src/test/java/us/kbase/test/auth2/lib/TemporarySessionDataTest.java index c11b6513..aec90adf 100644 --- a/src/test/java/us/kbase/test/auth2/lib/TemporarySessionDataTest.java +++ b/src/test/java/us/kbase/test/auth2/lib/TemporarySessionDataTest.java @@ -23,6 +23,7 @@ import us.kbase.auth2.lib.identity.RemoteIdentity; import us.kbase.auth2.lib.identity.RemoteIdentityDetails; import us.kbase.auth2.lib.identity.RemoteIdentityID; +import us.kbase.auth2.lib.token.MFAStatus; import us.kbase.test.auth2.TestCommon; public class TemporarySessionDataTest { @@ -52,11 +53,12 @@ public void constructLoginStart() throws Exception { assertThat("incorrect expires", ti.getExpires(), is(inst(20000))); assertThat("incorrect state", ti.getOAuth2State(), is(opt("stategoeshere"))); assertThat("incorrect pkce", ti.getPKCECodeVerifier(), is(opt("pkcegoeshere"))); - assertThat("incorrect user", ti.getUser(), is(Optional.empty())); - assertThat("incorrect idents", ti.getIdentities(), is(Optional.empty())); - assertThat("incorrect error", ti.getError(), is(Optional.empty())); - assertThat("incorrect error type", ti.getErrorType(), is(Optional.empty())); + assertThat("incorrect user", ti.getUser(), is(opt())); + assertThat("incorrect idents", ti.getIdentities(), is(opt())); + assertThat("incorrect error", ti.getError(), is(opt())); + assertThat("incorrect error type", ti.getErrorType(), is(opt())); assertThat("incorrect has error", ti.hasError(), is(false)); + assertThat("incorrect mfa", ti.getMFA(), is(opt())); } @Test @@ -64,7 +66,7 @@ public void constructLoginIdents() throws Exception { final UUID id = UUID.randomUUID(); final Instant now = Instant.now(); final TemporarySessionData ti = TemporarySessionData.create( - id, now, now.plusMillis(100000)).login(set(REMOTE1, REMOTE2)); + id, now, now.plusMillis(100000)).login(set(REMOTE1, REMOTE2), MFAStatus.USED); assertThat("incorrect op", ti.getOperation(), is(Operation.LOGINIDENTS)); assertThat("incorrect id", ti.getId(), is(id)); @@ -72,11 +74,12 @@ public void constructLoginIdents() throws Exception { assertThat("incorrect expires", ti.getExpires(), is(now.plusMillis(100000))); assertThat("incorrect state", ti.getOAuth2State(), is(ES)); assertThat("incorrect pkce", ti.getPKCECodeVerifier(), is(ES)); - assertThat("incorrect user", ti.getUser(), is(Optional.empty())); + assertThat("incorrect user", ti.getUser(), is(opt())); assertThat("incorrect idents", ti.getIdentities(), is(Optional.of(set(REMOTE2, REMOTE1)))); - assertThat("incorrect error", ti.getError(), is(Optional.empty())); - assertThat("incorrect error type", ti.getErrorType(), is(Optional.empty())); + assertThat("incorrect error", ti.getError(), is(opt())); + assertThat("incorrect error type", ti.getErrorType(), is(opt())); assertThat("incorrect has error", ti.hasError(), is(false)); + assertThat("incorrect mfa", ti.getMFA(), is(opt(MFAStatus.USED))); assertImmutable(ti); } @@ -95,11 +98,12 @@ public void constructWithError() throws Exception { assertThat("incorrect expires", ti.getExpires(), is(now.plusMillis(10000))); assertThat("incorrect state", ti.getOAuth2State(), is(ES)); assertThat("incorrect pkce", ti.getPKCECodeVerifier(), is(ES)); - assertThat("incorrect idents", ti.getIdentities(), is(Optional.empty())); - assertThat("incorrect user", ti.getUser(), is(Optional.empty())); + assertThat("incorrect idents", ti.getIdentities(), is(opt())); + assertThat("incorrect user", ti.getUser(), is(opt())); assertThat("incorrect error", ti.getError(), is(Optional.of("foo"))); assertThat("incorrect error type", ti.getErrorType(), is(Optional.of(ErrorType.DISABLED))); assertThat("incorrect has error", ti.hasError(), is(true)); + assertThat("incorrect mfa", ti.getMFA(), is(opt())); } @Test @@ -115,11 +119,12 @@ public void constructLinkStart() throws Exception { assertThat("incorrect expires", ti.getExpires(), is(now.plusMillis(10000))); assertThat("incorrect state", ti.getOAuth2State(), is(opt("somestate"))); assertThat("incorrect pkce", ti.getPKCECodeVerifier(), is(opt("pkce"))); - assertThat("incorrect idents", ti.getIdentities(), is(Optional.empty())); + assertThat("incorrect idents", ti.getIdentities(), is(opt())); assertThat("incorrect user", ti.getUser(), is(Optional.of(new UserName("bar")))); - assertThat("incorrect error", ti.getError(), is(Optional.empty())); - assertThat("incorrect error type", ti.getErrorType(), is(Optional.empty())); + assertThat("incorrect error", ti.getError(), is(opt())); + assertThat("incorrect error type", ti.getErrorType(), is(opt())); assertThat("incorrect has error", ti.hasError(), is(false)); + assertThat("incorrect mfa", ti.getMFA(), is(opt())); } @@ -139,9 +144,10 @@ public void constructLinkIdents() throws Exception { assertThat("incorrect pkce", ti.getPKCECodeVerifier(), is(ES)); assertThat("incorrect idents", ti.getIdentities(), is(Optional.of(set(REMOTE1, REMOTE2)))); assertThat("incorrect user", ti.getUser(), is(Optional.of(new UserName("bar")))); - assertThat("incorrect error", ti.getError(), is(Optional.empty())); - assertThat("incorrect error type", ti.getErrorType(), is(Optional.empty())); + assertThat("incorrect error", ti.getError(), is(opt())); + assertThat("incorrect error type", ti.getErrorType(), is(opt())); assertThat("incorrect has error", ti.hasError(), is(false)); + assertThat("incorrect mfa", ti.getMFA(), is(opt())); assertImmutable(ti); } @@ -161,9 +167,10 @@ public void constructExpireOverflows() throws Exception { assertThat("incorrect pkce", ti.getPKCECodeVerifier(), is(ES)); assertThat("incorrect idents", ti.getIdentities(), is(Optional.of(set(REMOTE1, REMOTE2)))); assertThat("incorrect user", ti.getUser(), is(Optional.of(new UserName("bar")))); - assertThat("incorrect error", ti.getError(), is(Optional.empty())); - assertThat("incorrect error type", ti.getErrorType(), is(Optional.empty())); + assertThat("incorrect error", ti.getError(), is(opt())); + assertThat("incorrect error type", ti.getErrorType(), is(opt())); assertThat("incorrect has error", ti.hasError(), is(false)); + assertThat("incorrect mfa", ti.getMFA(), is(opt())); assertImmutable(ti); } @@ -245,16 +252,23 @@ private void failConstructLoginStart( @Test public void constructLoginIdentsFailNulls() throws Exception { - failConstructLoginIdents(null, new NullPointerException("identities")); + final MFAStatus m = MFAStatus.UNKNOWN; + failConstructLoginIdents(null, m, new NullPointerException("identities")); + failConstructLoginIdents(set(REMOTE1), null, new NullPointerException("mfa")); failConstructLoginIdents( - set(REMOTE1, null), new NullPointerException("null item in identities")); - failConstructLoginIdents(set(), new IllegalArgumentException("empty identities")); + set(REMOTE1, null), m, new NullPointerException("null item in identities") + ); + failConstructLoginIdents(set(), m, new IllegalArgumentException("empty identities")); } - private void failConstructLoginIdents(final Set idents, final Exception e) { + private void failConstructLoginIdents( + final Set idents, + final MFAStatus mfa, + final Exception e + ) { try { TemporarySessionData.create(UUID.randomUUID(), Instant.now(), Instant.now()) - .login(idents); + .login(idents, mfa); fail("expected exception"); } catch (Exception got) { TestCommon.assertExceptionCorrect(got, e); diff --git a/src/test/java/us/kbase/test/auth2/lib/storage/mongo/MongoStorageTempSessionDataTest.java b/src/test/java/us/kbase/test/auth2/lib/storage/mongo/MongoStorageTempSessionDataTest.java index 6941afbf..6eb46091 100644 --- a/src/test/java/us/kbase/test/auth2/lib/storage/mongo/MongoStorageTempSessionDataTest.java +++ b/src/test/java/us/kbase/test/auth2/lib/storage/mongo/MongoStorageTempSessionDataTest.java @@ -23,6 +23,7 @@ import us.kbase.auth2.lib.UserName; import us.kbase.auth2.lib.token.IncomingHashedToken; import us.kbase.auth2.lib.token.IncomingToken; +import us.kbase.auth2.lib.token.MFAStatus; import us.kbase.test.auth2.TestCommon; public class MongoStorageTempSessionDataTest extends MongoStorageTester { @@ -54,13 +55,13 @@ public void storeAndGetLoginIdents() throws Exception { final UUID id = UUID.randomUUID(); final Instant now = Instant.now().truncatedTo(ChronoUnit.MILLIS); // mongo truncates final TemporarySessionData tsd = TemporarySessionData.create(id, now, now.plusSeconds(10)) - .login(set(REMOTE2)); + .login(set(REMOTE2), MFAStatus.USED); storage.storeTemporarySessionData(tsd, IncomingToken.hash("foobar")); assertThat("incorrect session data", storage.getTemporarySessionData( new IncomingToken("foobar").getHashedToken()), is( TemporarySessionData.create(id, now, now.plusSeconds(10)) - .login(set(REMOTE2)))); + .login(set(REMOTE2), MFAStatus.USED))); } @Test diff --git a/src/test/java/us/kbase/test/auth2/service/ServiceTestUtils.java b/src/test/java/us/kbase/test/auth2/service/ServiceTestUtils.java index 4469941a..3ffc9c4c 100644 --- a/src/test/java/us/kbase/test/auth2/service/ServiceTestUtils.java +++ b/src/test/java/us/kbase/test/auth2/service/ServiceTestUtils.java @@ -54,6 +54,7 @@ import us.kbase.auth2.lib.exceptions.AuthException; import us.kbase.auth2.lib.identity.IdentityProvider; import us.kbase.auth2.lib.token.IncomingToken; +import us.kbase.auth2.lib.token.MFAStatus; import us.kbase.auth2.lib.token.StoredToken; import us.kbase.auth2.lib.token.TokenName; import us.kbase.auth2.lib.token.TokenType; @@ -224,6 +225,7 @@ public static void checkReturnedToken( final Map customContext, final UserName userName, final TokenType type, + final MFAStatus mfa, final String name, final long lifetime, final boolean checkAgentContext) @@ -248,7 +250,7 @@ public static void checkReturnedToken( } checkStoredToken(manager, (String) uitoken.get("token"), id, created, customContext, - userName, type, name, lifetime); + userName, type, mfa, name, lifetime); } public static void checkStoredToken( @@ -259,9 +261,10 @@ public static void checkStoredToken( final Map customContext, final UserName userName, final TokenType type, + final MFAStatus mfa, final String name, - final long lifetime) - throws Exception { + final long lifetime + ) throws Exception { assertThat("incorrect token", token, is(RegexMatcher.matches("[A-Z2-7]{32}"))); @@ -291,6 +294,7 @@ public static void checkStoredToken( assertThat("incorrect id", st.getId(), is(UUID.fromString(id))); assertThat("incorrect name", st.getTokenName(), is(tn)); assertThat("incorrect user", st.getUserName(), is(userName)); + assertThat("incorrect mfa", st.getMFA(), is(mfa)); } // combine with above somehow? @@ -300,9 +304,10 @@ public static void checkStoredToken( final Map customContext, final UserName userName, final TokenType type, + final MFAStatus mfa, final String name, - final long lifetime) - throws Exception { + final long lifetime + ) throws Exception { assertThat("incorrect token", token, is(RegexMatcher.matches("[A-Z2-7]{32}"))); @@ -332,6 +337,7 @@ public static void checkStoredToken( assertThat("incorrect id", st.getId(), isA(UUID.class)); assertThat("incorrect name", st.getTokenName(), is(tn)); assertThat("incorrect user", st.getUserName(), is(userName)); + assertThat("incorrect mfa", st.getMFA(), is(mfa)); } public static void resetServer( diff --git a/src/test/java/us/kbase/test/auth2/service/api/TokenEndpointTest.java b/src/test/java/us/kbase/test/auth2/service/api/TokenEndpointTest.java index 4bdb2a34..0e449f99 100644 --- a/src/test/java/us/kbase/test/auth2/service/api/TokenEndpointTest.java +++ b/src/test/java/us/kbase/test/auth2/service/api/TokenEndpointTest.java @@ -44,6 +44,7 @@ import us.kbase.auth2.lib.exceptions.TestModeException; import us.kbase.auth2.lib.exceptions.UnauthorizedException; import us.kbase.auth2.lib.token.IncomingToken; +import us.kbase.auth2.lib.token.MFAStatus; import us.kbase.auth2.lib.token.NewToken; import us.kbase.auth2.lib.token.StoredToken; import us.kbase.auth2.lib.token.TokenName; @@ -226,7 +227,8 @@ public void createTokenNoCustomContext() throws Exception { @SuppressWarnings("unchecked") final Map response = res.readEntity(Map.class); ServiceTestUtils.checkReturnedToken(manager, response, Collections.emptyMap(), - new UserName("foo"), TokenType.AGENT, "whee", 7 * 24 * 3600 * 1000, false); + new UserName("foo"), TokenType.AGENT, MFAStatus.UNKNOWN, "whee", + 7 * 24 * 3600 * 1000, false); } @Test @@ -246,7 +248,8 @@ public void createTokenWithCustomContext() throws Exception { @SuppressWarnings("unchecked") final Map response = res.readEntity(Map.class); ServiceTestUtils.checkReturnedToken(manager, response, ImmutableMap.of("foo", "bar"), - new UserName("foo"), TokenType.AGENT, "whee", 7 * 24 * 3600 * 1000, false); + new UserName("foo"), TokenType.AGENT, MFAStatus.UNKNOWN, "whee", + 7 * 24 * 3600 * 1000, false); } @Test diff --git a/src/test/java/us/kbase/test/auth2/service/ui/LoginIntegrationTest.java b/src/test/java/us/kbase/test/auth2/service/ui/LoginIntegrationTest.java index 6f1db05b..0b5c6d86 100644 --- a/src/test/java/us/kbase/test/auth2/service/ui/LoginIntegrationTest.java +++ b/src/test/java/us/kbase/test/auth2/service/ui/LoginIntegrationTest.java @@ -75,6 +75,7 @@ import us.kbase.auth2.lib.identity.RemoteIdentityID; import us.kbase.auth2.lib.storage.exceptions.AuthStorageException; import us.kbase.auth2.lib.token.IncomingToken; +import us.kbase.auth2.lib.token.MFAStatus; import us.kbase.auth2.lib.token.TemporaryToken; import us.kbase.auth2.lib.token.TokenType; import us.kbase.auth2.lib.user.AuthUser; @@ -429,7 +430,7 @@ private void loginCompleteImmediateLoginMinimalInput(final String env) throws Ex saveTemporarySessionData(state, "pkceohgodohgod", "foobartoken"); - loginCompleteImmediateLoginStoreUser(authcode, "pkceohgodohgod", env); + loginCompleteImmediateLoginStoreUser(authcode, "pkceohgodohgod", env, MFAStatus.UNKNOWN); final WebTarget wt = loginCompleteSetUpWebTarget(authcode, state); final Builder b = wt.request() @@ -450,7 +451,7 @@ private void loginCompleteImmediateLoginMinimalInput(final String env) throws Ex assertThat("incorrect auth cookie less token", token, is(expectedtoken)); assertThat("incorrect token", token.getValue(), is(RegexMatcher.matches("[A-Z2-7]{32}"))); - loginCompleteImmediateLoginCheckToken(token); + loginCompleteImmediateLoginCheckToken(token, MFAStatus.UNKNOWN); } @Test @@ -468,7 +469,9 @@ public void loginCompleteImmediateLoginEmptyStringInput() throws Exception { saveTemporarySessionData(state, "pkcethisisinhumane", "foobartoken"); - loginCompleteImmediateLoginStoreUser(authcode, "pkcethisisinhumane", null); + loginCompleteImmediateLoginStoreUser( + authcode, "pkcethisisinhumane", null, MFAStatus.USED + ); final WebTarget wt = loginCompleteSetUpWebTargetEmptyError(authcode, state); final Response res = wt.request() @@ -488,7 +491,7 @@ public void loginCompleteImmediateLoginEmptyStringInput() throws Exception { assertThat("incorrect auth cookie less token", token, is(expectedtoken)); assertThat("incorrect token", token.getValue(), is(RegexMatcher.matches("[A-Z2-7]{32}"))); - loginCompleteImmediateLoginCheckToken(token); + loginCompleteImmediateLoginCheckToken(token, MFAStatus.USED); } @Test @@ -519,7 +522,7 @@ private void loginCompleteImmediateLoginRedirectAndTrueSession( saveTemporarySessionData(state, "pkcepkcepkcepkce", "foobartoken"); - loginCompleteImmediateLoginStoreUser(authcode, "pkcepkcepkcepkce", env); + loginCompleteImmediateLoginStoreUser(authcode, "pkcepkcepkcepkce", env, MFAStatus.NOT_USED); final WebTarget wt = loginCompleteSetUpWebTarget(authcode, state); final Builder b = wt.request() @@ -542,7 +545,7 @@ private void loginCompleteImmediateLoginRedirectAndTrueSession( assertThat("incorrect auth cookie less token", token, is(expectedtoken)); assertThat("incorrect token", token.getValue(), is(RegexMatcher.matches("[A-Z2-7]{32}"))); - loginCompleteImmediateLoginCheckToken(token); + loginCompleteImmediateLoginCheckToken(token, MFAStatus.NOT_USED); } @Test @@ -559,7 +562,7 @@ public void loginCompleteImmediateLoginRedirectAndFalseSession() throws Exceptio saveTemporarySessionData(state, "pkceoohhooohhhmm", "foobartoken"); - loginCompleteImmediateLoginStoreUser(authcode, "pkceoohhooohhhmm", null); + loginCompleteImmediateLoginStoreUser(authcode, "pkceoohhooohhhmm", null, MFAStatus.USED); final WebTarget wt = loginCompleteSetUpWebTarget(authcode, state); final Response res = wt.request() @@ -581,16 +584,17 @@ public void loginCompleteImmediateLoginRedirectAndFalseSession() throws Exceptio assertThat("incorrect token", token.getValue(), is(RegexMatcher.matches("[A-Z2-7]{32}"))); TestCommon.assertCloseTo(token.getMaxAge(), 14 * 24 * 3600, 10); - loginCompleteImmediateLoginCheckToken(token); + loginCompleteImmediateLoginCheckToken(token, MFAStatus.USED); } private void loginCompleteImmediateLoginStoreUser( final String authcode, final String pkce, - final String environment) + final String environment, + final MFAStatus mfa) throws Exception { final RemoteIdentity remoteIdentity = loginCompleteSetUpProviderMock( - authcode, pkce, environment); + authcode, pkce, environment, mfa); manager.storage.createUser(NewUser.getBuilder( new UserName("whee"), UID, new DisplayName("dn"), Instant.ofEpochMilli(20000), @@ -598,27 +602,30 @@ private void loginCompleteImmediateLoginStoreUser( .build()); } - private void loginCompleteImmediateLoginCheckToken(final NewCookie token) throws Exception { - checkLoginToken(token.getValue(), Collections.emptyMap(), new UserName("whee")); + private void loginCompleteImmediateLoginCheckToken(final NewCookie token, final MFAStatus mfa + ) throws Exception { + checkLoginToken(token.getValue(), Collections.emptyMap(), new UserName("whee"), mfa); } private void checkLoginToken( final Map uitoken, final Map customContext, - final UserName userName) + final UserName userName, + final MFAStatus mfa) throws Exception { ServiceTestUtils.checkReturnedToken(manager, uitoken, customContext, userName, - TokenType.LOGIN, null, 14 * 24 * 3600 * 1000, true); + TokenType.LOGIN, mfa, null, 14 * 24 * 3600 * 1000, true); } private void checkLoginToken( final String token, final Map customContext, - final UserName userName) + final UserName userName, + final MFAStatus mfa) throws Exception { ServiceTestUtils.checkStoredToken(manager, token, customContext, userName, TokenType.LOGIN, - null, 14 * 24 * 3600 * 1000); + mfa, null, 14 * 24 * 3600 * 1000); } private void assertLoginProcessTokensRemoved(final Response res) { @@ -685,7 +692,7 @@ private void loginCompleteDelayedMinimalInput(final String env) throws Exception saveTemporarySessionData(state, "pkceopraisethedarkgodsbelow", "foobartoken"); final RemoteIdentity remoteIdentity = loginCompleteSetUpProviderMock( - authcode, "pkceopraisethedarkgodsbelow", env); + authcode, "pkceopraisethedarkgodsbelow", env, MFAStatus.USED); final WebTarget wt = loginCompleteSetUpWebTarget(authcode, state); final Builder b = wt.request() @@ -710,7 +717,7 @@ private void loginCompleteDelayedMinimalInput(final String env) throws Exception assertEnvironmentCookieCorrect(res, env, 30 * 60); - loginCompleteDelayedCheckTempAndStateCookies(remoteIdentity, res); + loginCompleteDelayedCheckTempAndStateCookies(remoteIdentity, MFAStatus.USED, res); } @Test @@ -744,7 +751,7 @@ private void loginCompleteDelayedEmptyStringInputAndAlternateChoiceRedirect( saveTemporarySessionData(state, "pkceisinmybrainicanseeall", "foobartoken"); final RemoteIdentity remoteIdentity = loginCompleteSetUpProviderMock( - authcode, "pkceisinmybrainicanseeall", env); + authcode, "pkceisinmybrainicanseeall", env, MFAStatus.NOT_USED); final WebTarget wt = loginCompleteSetUpWebTarget(authcode, state); final Builder b = wt.request() @@ -771,7 +778,7 @@ private void loginCompleteDelayedEmptyStringInputAndAlternateChoiceRedirect( assertEnvironmentCookieCorrect(res, env, 30 * 60); - loginCompleteDelayedCheckTempAndStateCookies(remoteIdentity, res); + loginCompleteDelayedCheckTempAndStateCookies(remoteIdentity, MFAStatus.NOT_USED, res); } @Test @@ -810,7 +817,7 @@ private void loginCompleteDelayedLoginRedirectAndTrueSession( saveTemporarySessionData(state, "pkcuwgahngalftaghn", "foobartoken"); final RemoteIdentity remoteIdentity = loginCompleteSetUpProviderMock( - authcode, "pkcuwgahngalftaghn", env); + authcode, "pkcuwgahngalftaghn", env, MFAStatus.UNKNOWN); final WebTarget wt = loginCompleteSetUpWebTarget(authcode, state); final Builder b = wt.request() @@ -840,7 +847,7 @@ private void loginCompleteDelayedLoginRedirectAndTrueSession( assertEnvironmentCookieCorrect(res, env, 30 * 60); - loginCompleteDelayedCheckTempAndStateCookies(remoteIdentity, res); + loginCompleteDelayedCheckTempAndStateCookies(remoteIdentity, MFAStatus.UNKNOWN, res); } @Test @@ -859,7 +866,7 @@ public void loginCompleteDelayedLoginRedirectAndFalseSession() throws Exception saveTemporarySessionData(state, "pkceifeelmoistandsprightly", "foobartoken"); final RemoteIdentity remoteIdentity = loginCompleteSetUpProviderMock( - authcode, "pkceifeelmoistandsprightly", null); + authcode, "pkceifeelmoistandsprightly", null, MFAStatus.NOT_USED); final WebTarget wt = loginCompleteSetUpWebTarget(authcode, state); final Response res = wt.request() @@ -885,11 +892,12 @@ public void loginCompleteDelayedLoginRedirectAndFalseSession() throws Exception assertThat("incorrect session cookie less max age", session, is(expectedsession)); TestCommon.assertCloseTo(session.getMaxAge(), 30 * 60, 10); - loginCompleteDelayedCheckTempAndStateCookies(remoteIdentity, res); + loginCompleteDelayedCheckTempAndStateCookies(remoteIdentity, MFAStatus.NOT_USED, res); } private void loginCompleteDelayedCheckTempAndStateCookies( final RemoteIdentity remoteIdentity, + final MFAStatus mfa, final Response res) throws Exception { @@ -903,6 +911,7 @@ private void loginCompleteDelayedCheckTempAndStateCookies( new IncomingToken(tempCookie.getValue()).getHashedToken()); assertThat("incorrect stored ids", tis.getIdentities().get(), is(set(remoteIdentity))); + assertThat("incorrect mfa", tis.getMFA().get(), is(mfa)); } private WebTarget loginCompleteSetUpWebTarget(final String authcode, final String state) { @@ -930,7 +939,8 @@ private WebTarget loginCompleteSetUpWebTargetEmptyError( private RemoteIdentity loginCompleteSetUpProviderMock( final String authcode, final String pkce, - final String environment) + final String environment, + final MFAStatus mfa) throws Exception { final IdentityProvider provmock = MockIdentityProviderFactory.MOCKS.get("prov1"); @@ -938,7 +948,7 @@ private RemoteIdentity loginCompleteSetUpProviderMock( new RemoteIdentityID("prov1", "prov1id"), new RemoteIdentityDetails("user", "full", "email@email.com")); when(provmock.getIdentities(authcode, pkce, false, environment)) - .thenReturn(IdentityProviderResponse.from(remoteIdentity)); + .thenReturn(IdentityProviderResponse.from(remoteIdentity, mfa)); return remoteIdentity; } @@ -1154,7 +1164,7 @@ public void loginChoice3Create2Login() throws Exception { final TemporarySessionData data = TemporarySessionData.create( UUID.randomUUID(), Instant.ofEpochMilli(1493000000000L), 10000000000000L) - .login(idents); + .login(idents, MFAStatus.USED); final TemporaryToken tt = new TemporaryToken(data, "this is a token"); @@ -1280,7 +1290,7 @@ public void loginChoice2LoginWithRedirectAndLoginDisabled() throws Exception { final TemporarySessionData data = TemporarySessionData.create( UUID.randomUUID(), Instant.ofEpochMilli(1493000000000L), 10000000000000L) - .login(idents); + .login(idents, MFAStatus.NOT_USED); final TemporaryToken tt = new TemporaryToken(data, "this is a token"); @@ -1378,7 +1388,7 @@ private void loginChoice2CreateAndLoginDisabled(final String env) throws Excepti } final TemporarySessionData data = TemporarySessionData.create( UUID.randomUUID(), Instant.ofEpochMilli(1493000000000L), 10000000000000L) - .login(idents); + .login(idents, MFAStatus.UNKNOWN); final TemporaryToken tt = new TemporaryToken(data, "this is a token"); @@ -1464,7 +1474,7 @@ private void loginChoice2CreateWithRedirectURL(final String env, final String ur } final TemporarySessionData data = TemporarySessionData.create( UUID.randomUUID(), Instant.ofEpochMilli(1493000000000L), 10000000000000L) - .login(idents); + .login(idents, MFAStatus.USED); final TemporaryToken tt = new TemporaryToken(data, "this is a token"); @@ -1685,8 +1695,13 @@ public void loginChoiceFailBadRedirect() throws Exception { public void loginCancelPOST() throws Exception { final TemporarySessionData data = TemporarySessionData.create( UUID.randomUUID(), Instant.ofEpochMilli(1493000000000L), 10000000000000L) - .login(set(new RemoteIdentity(new RemoteIdentityID("prov", "id"), - new RemoteIdentityDetails("user", "full", "e@g.com")))); + .login( + set(new RemoteIdentity( + new RemoteIdentityID("prov", "id"), + new RemoteIdentityDetails("user", "full", "e@g.com") + )), + MFAStatus.UNKNOWN + ); final TemporaryToken tt = new TemporaryToken(data, "this is a token"); @@ -1710,8 +1725,13 @@ public void loginCancelPOST() throws Exception { public void loginCancelDELETE() throws Exception { final TemporarySessionData data = TemporarySessionData.create( UUID.randomUUID(), Instant.ofEpochMilli(1493000000000L), 10000000000000L) - .login(set(new RemoteIdentity(new RemoteIdentityID("prov", "id"), - new RemoteIdentityDetails("user", "full", "e@g.com")))); + .login( + set(new RemoteIdentity( + new RemoteIdentityID("prov", "id"), + new RemoteIdentityDetails("user", "full", "e@g.com") + )), + MFAStatus.UNKNOWN + ); final TemporaryToken tt = new TemporaryToken(data, "this is a token"); @@ -1769,7 +1789,7 @@ public void loginPickFormMinimalInputWithEnvironment() throws Exception { } private void loginPickFormMinimalInput(final String env) throws Exception { - final TemporaryToken tt = loginPickSetup(); + final TemporaryToken tt = loginPickSetup(MFAStatus.UNKNOWN); final URI target = UriBuilder.fromUri(host).path("/login/pick").build(); @@ -1785,7 +1805,7 @@ private void loginPickFormMinimalInput(final String env) throws Exception { assertThat("incorrect response code", res.getStatus(), is(303)); assertThat("incorrect target uri", res.getLocation(), is(new URI(host + "/me"))); - loginPickOrCreateCheckSessionToken(res); + loginPickOrCreateCheckSessionToken(res, MFAStatus.UNKNOWN); final AuthUser u = manager.storage.getUser(new UserName("u1")); TestCommon.assertCloseToNow(u.getLastLogin().get()); @@ -1806,7 +1826,7 @@ public void loginPickJSONMinimalInputWithException() throws Exception { } private void loginPickJSONMinimalInput(final String env) throws Exception { - final TemporaryToken tt = loginPickSetup(); + final TemporaryToken tt = loginPickSetup(MFAStatus.USED); final URI target = UriBuilder.fromUri(host).path("/login/pick").build(); @@ -1826,7 +1846,7 @@ private void loginPickJSONMinimalInput(final String env) throws Exception { @SuppressWarnings("unchecked") final Map token = (Map) response.get("token"); - checkLoginToken(token, Collections.emptyMap(), new UserName("u1")); + checkLoginToken(token, Collections.emptyMap(), new UserName("u1"), MFAStatus.USED); final AuthUser u = manager.storage.getUser(new UserName("u1")); TestCommon.assertCloseToNow(u.getLastLogin().get()); @@ -1847,7 +1867,7 @@ public void loginPickFormMaximalInputWithEnvironment() throws Exception { } private void loginPickFormMaximalInput(final String env, final String url) throws Exception { - final TemporaryToken tt = loginPickSetup(); + final TemporaryToken tt = loginPickSetup(MFAStatus.NOT_USED); final URI target = UriBuilder.fromUri(host).path("/login/pick").build(); @@ -1869,7 +1889,9 @@ private void loginPickFormMaximalInput(final String env, final String url) throw assertThat("incorrect response code", res.getStatus(), is(303)); assertThat("incorrect target uri", res.getLocation(), is(new URI(url))); - loginPickOrCreateCheckExtendedToken(res, ImmutableMap.of("a", "1", "b", "2")); + loginPickOrCreateCheckExtendedToken( + res, ImmutableMap.of("a", "1", "b", "2"), MFAStatus.NOT_USED + ); final AuthUser u = manager.storage.getUser(new UserName("u1")); TestCommon.assertCloseToNow(u.getLastLogin().get()); @@ -1893,7 +1915,7 @@ public void loginPickJsonMaximalInputWithEnvironment() throws Exception { } private void loginPickJsonMaximalInput(final String env, final String url) throws Exception { - final TemporaryToken tt = loginPickSetup(); + final TemporaryToken tt = loginPickSetup(MFAStatus.UNKNOWN); final URI target = UriBuilder.fromUri(host).path("/login/pick").build(); @@ -1918,7 +1940,9 @@ private void loginPickJsonMaximalInput(final String env, final String url) throw @SuppressWarnings("unchecked") final Map token = (Map) response.get("token"); - checkLoginToken(token, ImmutableMap.of("a", "1", "b", "2"), new UserName("u1")); + checkLoginToken( + token, ImmutableMap.of("a", "1", "b", "2"), new UserName("u1"), MFAStatus.UNKNOWN + ); final AuthUser u = manager.storage.getUser(new UserName("u1")); TestCommon.assertCloseToNow(u.getLastLogin().get()); @@ -1934,7 +1958,7 @@ private void loginPickJsonMaximalInput(final String env, final String url) throw @Test public void loginPickFormEmptyStrings() throws Exception { - final TemporaryToken tt = loginPickSetup(); + final TemporaryToken tt = loginPickSetup(MFAStatus.USED); final URI target = UriBuilder.fromUri(host).path("/login/pick").build(); @@ -1953,7 +1977,7 @@ public void loginPickFormEmptyStrings() throws Exception { assertThat("incorrect response code", res.getStatus(), is(303)); assertThat("incorrect target uri", res.getLocation(), is(new URI(host + "/me"))); - loginPickOrCreateCheckSessionToken(res); + loginPickOrCreateCheckSessionToken(res, MFAStatus.USED); final AuthUser u = manager.storage.getUser(new UserName("u1")); TestCommon.assertCloseToNow(u.getLastLogin().get()); @@ -1966,7 +1990,7 @@ public void loginPickFormEmptyStrings() throws Exception { @Test public void loginPickJsonEmptyData() throws Exception { - final TemporaryToken tt = loginPickSetup(); + final TemporaryToken tt = loginPickSetup(MFAStatus.NOT_USED); final URI target = UriBuilder.fromUri(host).path("/login/pick").build(); @@ -1991,7 +2015,7 @@ public void loginPickJsonEmptyData() throws Exception { @SuppressWarnings("unchecked") final Map token = (Map) response.get("token"); - checkLoginToken(token, Collections.emptyMap(), new UserName("u1")); + checkLoginToken(token, Collections.emptyMap(), new UserName("u1"), MFAStatus.NOT_USED); final AuthUser u = manager.storage.getUser(new UserName("u1")); TestCommon.assertCloseToNow(u.getLastLogin().get()); @@ -2306,7 +2330,8 @@ public void loginPickFailEmptyPolicyID() throws Exception { private void loginPickOrCreateCheckExtendedToken( final Response res, - final Map customContext) + final Map customContext, + final MFAStatus mfa) throws Exception { assertLoginProcessTokensRemoved(res); @@ -2316,10 +2341,10 @@ private void loginPickOrCreateCheckExtendedToken( assertThat("incorrect auth cookie less token", token, is(expectedtoken)); TestCommon.assertCloseTo(token.getMaxAge(), 14 * 24 * 3600, 10); - checkLoginToken(token.getValue(), customContext, new UserName("u1")); + checkLoginToken(token.getValue(), customContext, new UserName("u1"), mfa); } - private void loginPickOrCreateCheckSessionToken(final Response res) + private void loginPickOrCreateCheckSessionToken(final Response res, final MFAStatus mfa) throws Exception, MissingParameterException, IllegalParameterException { assertLoginProcessTokensRemoved(res); @@ -2328,7 +2353,7 @@ private void loginPickOrCreateCheckSessionToken(final Response res) "/", null, "authtoken", -1, false); assertThat("incorrect auth cookie less token", token, is(expectedtoken)); - checkLoginToken(token.getValue(), Collections.emptyMap(), new UserName("u1")); + checkLoginToken(token.getValue(), Collections.emptyMap(), new UserName("u1"), mfa); } private Builder loginPickOrCreateRequestBuilder( @@ -2344,7 +2369,7 @@ private Builder loginPickOrCreateRequestBuilder( return req; } - private TemporaryToken loginPickSetup() throws Exception { + private TemporaryToken loginPickSetup(final MFAStatus mfa) throws Exception { final IncomingToken admintoken = ServiceTestUtils.getAdminToken(manager); @@ -2354,7 +2379,7 @@ private TemporaryToken loginPickSetup() throws Exception { final TemporarySessionData data = TemporarySessionData.create( UUID.randomUUID(), Instant.ofEpochMilli(1493000000000L), 10000000000000L) - .login(set(REMOTE1, REMOTE2, REMOTE3)); + .login(set(REMOTE1, REMOTE2, REMOTE3), mfa); final TemporaryToken tt = new TemporaryToken(data, "this is a token"); @@ -2380,7 +2405,7 @@ public void loginCreateFormMinimalInputWithEnvironment() throws Exception { } private void loginCreateFormMinimalInput(final String env) throws Exception { - final TemporaryToken tt = loginChoiceSetup(); + final TemporaryToken tt = loginCreateSetup(MFAStatus.UNKNOWN); final URI target = UriBuilder.fromUri(host).path("/login/create").build(); @@ -2399,7 +2424,7 @@ private void loginCreateFormMinimalInput(final String env) throws Exception { assertThat("incorrect response code", res.getStatus(), is(303)); assertThat("incorrect target uri", res.getLocation(), is(new URI(host + "/me"))); - loginPickOrCreateCheckSessionToken(res); + loginPickOrCreateCheckSessionToken(res, MFAStatus.UNKNOWN); final AuthUser u = manager.storage.getUser(new UserName("u1")); TestCommon.assertCloseToNow(u.getLastLogin().get()); @@ -2423,7 +2448,7 @@ public void loginCreateJSONMinimalInputWithEnvironment() throws Exception { private void loginCreateJSONMinimalInput(final String env) throws Exception { - final TemporaryToken tt = loginChoiceSetup(); + final TemporaryToken tt = loginCreateSetup(MFAStatus.USED); final URI target = UriBuilder.fromUri(host).path("/login/create").build(); @@ -2448,7 +2473,7 @@ private void loginCreateJSONMinimalInput(final String env) throws Exception { @SuppressWarnings("unchecked") final Map token = (Map) response.get("token"); - checkLoginToken(token, Collections.emptyMap(), new UserName("u1")); + checkLoginToken(token, Collections.emptyMap(), new UserName("u1"), MFAStatus.USED); final AuthUser u = manager.storage.getUser(new UserName("u1")); TestCommon.assertCloseToNow(u.getLastLogin().get()); @@ -2471,7 +2496,7 @@ public void loginCreateFormMaximalInputFromEnvironment() throws Exception { } private void loginCreateFormMaximalInput(final String env, final String url) throws Exception { - final TemporaryToken tt = loginChoiceSetup(); + final TemporaryToken tt = loginCreateSetup(MFAStatus.NOT_USED); final URI target = UriBuilder.fromUri(host).path("/login/create").build(); @@ -2496,7 +2521,9 @@ private void loginCreateFormMaximalInput(final String env, final String url) thr assertThat("incorrect response code", res.getStatus(), is(303)); assertThat("incorrect target uri", res.getLocation(), is(new URI(url))); - loginPickOrCreateCheckExtendedToken(res, ImmutableMap.of("a", "1", "b", "2")); + loginPickOrCreateCheckExtendedToken( + res, ImmutableMap.of("a", "1", "b", "2"), MFAStatus.NOT_USED + ); final AuthUser u = manager.storage.getUser(new UserName("u1")); TestCommon.assertCloseToNow(u.getLastLogin().get()); @@ -2511,7 +2538,6 @@ private void loginCreateFormMaximalInput(final String env, final String url) thr assertNoTempToken(tt); } - @Test public void loginCreateJSONMaximalInput() throws Exception { loginCreateJSONMaximalInput(null, "https://foo.com/baz/bat"); @@ -2523,7 +2549,7 @@ public void loginCreateJSONMaximalInputWithEnvironment() throws Exception { } private void loginCreateJSONMaximalInput(final String env, final String url) throws Exception { - final TemporaryToken tt = loginChoiceSetup(); + final TemporaryToken tt = loginCreateSetup(MFAStatus.UNKNOWN); final URI target = UriBuilder.fromUri(host).path("/login/create").build(); @@ -2555,7 +2581,9 @@ private void loginCreateJSONMaximalInput(final String env, final String url) thr @SuppressWarnings("unchecked") final Map token = (Map) response.get("token"); - checkLoginToken(token, ImmutableMap.of("a", "1", "b", "2"), new UserName("u1")); + checkLoginToken( + token, ImmutableMap.of("a", "1", "b", "2"), new UserName("u1"), MFAStatus.UNKNOWN + ); final AuthUser u = manager.storage.getUser(new UserName("u1")); TestCommon.assertCloseToNow(u.getLastLogin().get()); @@ -2573,7 +2601,7 @@ private void loginCreateJSONMaximalInput(final String env, final String url) thr @Test public void loginCreateFormEmptyStrings() throws Exception { - final TemporaryToken tt = loginChoiceSetup(); + final TemporaryToken tt = loginCreateSetup(MFAStatus.USED); final URI target = UriBuilder.fromUri(host).path("/login/create").build(); @@ -2597,7 +2625,7 @@ public void loginCreateFormEmptyStrings() throws Exception { assertThat("incorrect response code", res.getStatus(), is(303)); assertThat("incorrect target uri", res.getLocation(), is(new URI(host + "/me"))); - loginPickOrCreateCheckSessionToken(res); + loginPickOrCreateCheckSessionToken(res, MFAStatus.USED); final AuthUser u = manager.storage.getUser(new UserName("u1")); TestCommon.assertCloseToNow(u.getLastLogin().get()); @@ -2612,7 +2640,7 @@ public void loginCreateFormEmptyStrings() throws Exception { @Test public void loginCreateJSONEmptyInput() throws Exception { - final TemporaryToken tt = loginChoiceSetup(); + final TemporaryToken tt = loginCreateSetup(MFAStatus.NOT_USED); final URI target = UriBuilder.fromUri(host).path("/login/create").build(); @@ -2645,7 +2673,7 @@ public void loginCreateJSONEmptyInput() throws Exception { @SuppressWarnings("unchecked") final Map token = (Map) response.get("token"); - checkLoginToken(token, Collections.emptyMap(), new UserName("u1")); + checkLoginToken(token, Collections.emptyMap(), new UserName("u1"), MFAStatus.NOT_USED); final AuthUser u = manager.storage.getUser(new UserName("u1")); TestCommon.assertCloseToNow(u.getLastLogin().get()); @@ -2689,7 +2717,7 @@ public void loginCreateFailEmptyID() throws Exception { @Test public void loginCreateFailBadToken() throws Exception { - loginChoiceSetup(); + loginCreateSetup(MFAStatus.UNKNOWN); final URI target = UriBuilder.fromUri(host) .path("/login/create") @@ -2884,7 +2912,7 @@ public void loginCreateFailBadEmail() throws Exception { "e1@g.@com")); } - private TemporaryToken loginChoiceSetup() throws Exception { + private TemporaryToken loginCreateSetup(final MFAStatus mfa) throws Exception { final IncomingToken admintoken = ServiceTestUtils.getAdminToken(manager); enableLogin(host, admintoken); @@ -2893,7 +2921,7 @@ private TemporaryToken loginChoiceSetup() throws Exception { final TemporarySessionData data = TemporarySessionData.create( UUID.randomUUID(), Instant.ofEpochMilli(1493000000000L), 10000000000000L) - .login(set(REMOTE1, REMOTE2)); + .login(set(REMOTE1, REMOTE2), mfa); final TemporaryToken tt = new TemporaryToken(data, "this is a token"); diff --git a/src/test/java/us/kbase/test/auth2/service/ui/SimpleEndpointsTest.java b/src/test/java/us/kbase/test/auth2/service/ui/SimpleEndpointsTest.java index 12b3b0ba..d863cfa5 100644 --- a/src/test/java/us/kbase/test/auth2/service/ui/SimpleEndpointsTest.java +++ b/src/test/java/us/kbase/test/auth2/service/ui/SimpleEndpointsTest.java @@ -55,6 +55,7 @@ import us.kbase.auth2.lib.exceptions.NoTokenProvidedException; import us.kbase.auth2.lib.exceptions.PasswordMismatchException; import us.kbase.auth2.lib.token.IncomingToken; +import us.kbase.auth2.lib.token.MFAStatus; import us.kbase.auth2.lib.token.StoredToken; import us.kbase.auth2.lib.token.TokenType; import us.kbase.auth2.lib.user.LocalUser; @@ -521,7 +522,8 @@ public void localLoginSuccessMinimalInput() throws Exception { assertThat("incorrect auth cookie less token", token, is(expectedtoken)); ServiceTestUtils.checkStoredToken(manager, token.getValue(), Collections.emptyMap(), - new UserName("whoo"), TokenType.LOGIN, null, 14 * 24 * 3600 * 1000); + new UserName("whoo"), TokenType.LOGIN, MFAStatus.UNKNOWN, null, + 14 * 24 * 3600 * 1000); } @Test @@ -556,7 +558,8 @@ public void localLoginSuccessMaximalInput() throws Exception { ServiceTestUtils.checkStoredToken(manager, token.getValue(), ImmutableMap.of("foo", "bar", "baz", "bat"), - new UserName("whoo"), TokenType.LOGIN, null, 14 * 24 * 3600 * 1000); + new UserName("whoo"), TokenType.LOGIN, MFAStatus.UNKNOWN, null, + 14 * 24 * 3600 * 1000); } @Test diff --git a/src/test/java/us/kbase/test/auth2/service/ui/TokensTest.java b/src/test/java/us/kbase/test/auth2/service/ui/TokensTest.java index ecf2a3b6..5f64fa01 100644 --- a/src/test/java/us/kbase/test/auth2/service/ui/TokensTest.java +++ b/src/test/java/us/kbase/test/auth2/service/ui/TokensTest.java @@ -51,6 +51,7 @@ import us.kbase.auth2.lib.exceptions.NoSuchTokenException; import us.kbase.auth2.lib.exceptions.NoTokenProvidedException; import us.kbase.auth2.lib.token.IncomingToken; +import us.kbase.auth2.lib.token.MFAStatus; import us.kbase.auth2.lib.token.StoredToken; import us.kbase.auth2.lib.token.TokenName; import us.kbase.auth2.lib.token.TokenType; @@ -389,7 +390,8 @@ public void createTokenMinimalInput() throws Exception { assertThat("incorrect expires", expires, is(created + 90 * 24 * 3600 * 1000L)); ServiceTestUtils.checkStoredToken(manager, newtoken, id, created, Collections.emptyMap(), - new UserName("whoo"), TokenType.DEV, "foo", 90 * 24 * 3600 * 1000L); + new UserName("whoo"), TokenType.DEV, MFAStatus.UNKNOWN, "foo", + 90 * 24 * 3600 * 1000L); final Builder req2 = wt.request() @@ -403,7 +405,8 @@ public void createTokenMinimalInput() throws Exception { assertThat("incorrect response code", res.getStatus(), is(200)); ServiceTestUtils.checkReturnedToken(manager, json, Collections.emptyMap(), - new UserName("whoo"), TokenType.DEV, "foo", 90 * 24 * 3600 * 1000L, true); + new UserName("whoo"), TokenType.DEV, MFAStatus.UNKNOWN, "foo", + 90 * 24 * 3600 * 1000L, true); } @Test @@ -459,7 +462,8 @@ public void createTokenMaximalInput() throws Exception { ServiceTestUtils.checkStoredToken(manager, newtoken, id, created, ImmutableMap.of("foo", "bar", "baz", "bat"), - new UserName("whoo"), TokenType.SERV, "foo", 100_000_000L * 24 * 3600 * 1000L); + new UserName("whoo"), TokenType.SERV, MFAStatus.UNKNOWN, "foo", + 100_000_000L * 24 * 3600 * 1000L); final Builder req2 = wt.request() @@ -477,7 +481,7 @@ public void createTokenMaximalInput() throws Exception { ServiceTestUtils.checkReturnedToken(manager, json, ImmutableMap.of("foo", "bar", "baz", "bat"), - new UserName("whoo"), TokenType.SERV, "foo", + new UserName("whoo"), TokenType.SERV, MFAStatus.UNKNOWN, "foo", 100_000_000L * 24 * 3600 * 1000L, true); } }