Skip to content

Commit

Permalink
When authing an LDAP user, try to find shadow user by email.
Browse files Browse the repository at this point in the history
[#108824986] https://www.pivotaltracker.com/story/show/108824986

Signed-off-by: Jeremy Coffield <jcoffield@pivotal.io>
  • Loading branch information
Paul Warren committed Dec 3, 2015
1 parent 62abf63 commit bac30e2
Show file tree
Hide file tree
Showing 6 changed files with 106 additions and 8 deletions.
Expand Up @@ -96,6 +96,11 @@ public Authentication authenticate(Authentication request) throws Authentication
boolean addnew = false;
try {
UaaUser temp = userDatabase.retrieveUserByName(user.getUsername(), getOrigin());

if(temp == null) {
temp = userDatabase.retrieveUserByEmail(user.getEmail(), getOrigin());
}

if (temp != null) {
user = temp;
} else {
Expand Down
Expand Up @@ -57,6 +57,11 @@ public UaaUser retrieveUserById(String id) throws UsernameNotFoundException {
return u;
}

@Override
public UaaUser retrieveUserByEmail(String email, String origin) throws UsernameNotFoundException {
return users.values().stream().filter(u -> origin.equalsIgnoreCase(u.getOrigin()) && email.equalsIgnoreCase(u.getEmail())).findAny().orElse(null);
}

public UaaUser updateUser(String userId, UaaUser user) throws UsernameNotFoundException {

if (!ids.containsKey(userId)) {
Expand Down
Expand Up @@ -14,7 +14,6 @@

import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
Expand All @@ -24,6 +23,7 @@

import org.cloudfoundry.identity.uaa.zone.IdentityZoneHolder;
import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.dao.IncorrectResultSizeDataAccessException;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.security.core.GrantedAuthority;
Expand All @@ -47,6 +47,9 @@ public class JdbcUaaUserDatabase implements UaaUserDatabase {
public static final String DEFAULT_USER_BY_ID_QUERY = "select " + USER_FIELDS + "from users "
+ "where id = ? and active=?";

public static final String DEFAULT_USER_BY_EMAIL_AND_ORIGIN_QUERY = "select " + USER_FIELDS + "from users "
+ "where lower(email)=? and active=? and origin=?";

private String userAuthoritiesQuery = null;

private String userByUserNameQuery = DEFAULT_USER_BY_USERNAME_QUERY;
Expand Down Expand Up @@ -92,6 +95,24 @@ public UaaUser retrieveUserById(String id) throws UsernameNotFoundException {
}
}

@Override
public UaaUser retrieveUserByEmail(String email, String origin) throws UsernameNotFoundException {
try {
List<UaaUser> results = jdbcTemplate.query(DEFAULT_USER_BY_EMAIL_AND_ORIGIN_QUERY, mapper, email.toLowerCase(Locale.US), true, origin);
if(results.size() == 0) {
return null;
}
else if(results.size() == 1) {
return results.get(0);
}
else {
throw new IncorrectResultSizeDataAccessException(String.format("Multiple users match email=%s origin=%s", email, origin), 1, results.size());
}
} catch (EmptyResultDataAccessException e) {
throw new UsernameNotFoundException(email);
}
}

private final class UaaUserRowMapper implements RowMapper<UaaUser> {
@Override
public UaaUser mapRow(ResultSet rs, int rowNum) throws SQLException {
Expand Down
Expand Up @@ -21,4 +21,6 @@ public interface UaaUserDatabase {
UaaUser retrieveUserByName(String username, String origin) throws UsernameNotFoundException;

UaaUser retrieveUserById(String id) throws UsernameNotFoundException;

UaaUser retrieveUserByEmail(String email, String origin) throws UsernameNotFoundException;
}
Expand Up @@ -3,6 +3,7 @@
import org.cloudfoundry.identity.uaa.authentication.UaaAuthentication;
import org.cloudfoundry.identity.uaa.authentication.UaaAuthenticationDetails;
import org.cloudfoundry.identity.uaa.authentication.event.UserAuthenticationSuccessEvent;
import org.cloudfoundry.identity.uaa.ldap.ExtendedLdapUserDetails;
import org.cloudfoundry.identity.uaa.ldap.extension.ExtendedLdapUserImpl;
import org.cloudfoundry.identity.uaa.user.Mailable;
import org.cloudfoundry.identity.uaa.user.UaaUser;
Expand All @@ -22,11 +23,16 @@

import java.util.HashMap;

import static org.hamcrest.CoreMatchers.not;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertThat;
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq;
import static org.mockito.Matchers.isA;
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
Expand Down Expand Up @@ -68,14 +74,9 @@ public void setUp() throws Exception {
private void mockUaaWithUser() {
applicationEventPublisher = mock(ApplicationEventPublisher.class);

user = mock(UaaUser.class);
when(user.getUsername()).thenReturn(userName);
when(user.getId()).thenReturn(userId);
when(user.getOrigin()).thenReturn(origin);

uaaUserDatabase = mock(UaaUserDatabase.class);
when(uaaUserDatabase.retrieveUserById(eq(userId))).thenReturn(user);
when(uaaUserDatabase.retrieveUserByName(eq(userName),eq(origin))).thenReturn(user);

user = addUserToDb(userName, userId, origin, "test@email.org");

inputAuth = mock(Authentication.class);
when(inputAuth.getPrincipal()).thenReturn(userDetails);
Expand All @@ -84,6 +85,18 @@ private void mockUaaWithUser() {
setupManager();
}

private UaaUser addUserToDb(String userName, String userId, String origin, String email) {
UaaUser user = mock(UaaUser.class);
when(user.getUsername()).thenReturn(userName);
when(user.getId()).thenReturn(userId);
when(user.getOrigin()).thenReturn(origin);
when(user.getEmail()).thenReturn(email);

when(this.uaaUserDatabase.retrieveUserById(eq(userId))).thenReturn(user);
when(this.uaaUserDatabase.retrieveUserByName(eq(userName),eq(origin))).thenReturn(user);
return user;
}

private void setupManager() {
manager.setOrigin(origin);
manager.setBeanName(beanName);
Expand Down Expand Up @@ -335,6 +348,48 @@ public void testAuthenticateCreateUserWithUserDetailsPrincipal() throws Exceptio
assertEquals(userName, event.getUser().getExternalId());
}

@Test
public void testAuthenticateInvitedUserWithoutAcceptance() throws Exception {
String username = "guyWhoDoesNotAcceptInvites";
String origin = "ldap";
String email = "guy@ldap.org";

UserDetails ldapUserDetails = mock(ExtendedLdapUserDetails.class, withSettings().extraInterfaces(Mailable.class));
when(ldapUserDetails.getUsername()).thenReturn(username);
when(ldapUserDetails.getPassword()).thenReturn(password);
when(ldapUserDetails.getAuthorities()).thenReturn(null);
when(ldapUserDetails.isAccountNonExpired()).thenReturn(true);
when(ldapUserDetails.isAccountNonLocked()).thenReturn(true);
when(ldapUserDetails.isCredentialsNonExpired()).thenReturn(true);
when(ldapUserDetails.isEnabled()).thenReturn(true);
when(((Mailable) ldapUserDetails).getEmailAddress()).thenReturn(email);

// Invited users are created with their email as their username.
UaaUser invitedUser = addUserToDb(email, userId, origin, email);
when(invitedUser.modifyAttributes(anyString(), anyString(), anyString(), anyString())).thenReturn(invitedUser);

manager = new LdapLoginAuthenticationManager();
setupManager();
manager.setOrigin(origin);

when(uaaUserDatabase.retrieveUserByName(eq(this.userName),eq(origin)))
.thenReturn(null)
.thenReturn(invitedUser); // This is only required to failure comprehensible. Otherwise get null source error.
when(uaaUserDatabase.retrieveUserByEmail(eq(email), eq(origin)))
.thenReturn(invitedUser);

Authentication ldapAuth = mock(Authentication.class);
when(ldapAuth.getPrincipal()).thenReturn(ldapUserDetails);

manager.authenticate(ldapAuth);

userArgumentCaptor = ArgumentCaptor.forClass(ApplicationEvent.class);
verify(applicationEventPublisher, atLeastOnce()).publishEvent(userArgumentCaptor.capture());

for(ApplicationEvent event : userArgumentCaptor.getAllValues()) {
assertNotEquals(event.getClass(), NewUserAuthenticatedEvent.class);
}
}

@Test
public void testAuthenticateUserExists() throws Exception {
Expand Down
Expand Up @@ -55,6 +55,16 @@ public UaaUser retrieveUserById(String id) throws UsernameNotFoundException {
}
}

@Override
public UaaUser retrieveUserByEmail(String email, String origin) throws UsernameNotFoundException {
if (email.equals(user.getEmail()) && origin.equals(user.getOrigin())) {
return user;
}
else {
throw new UsernameNotFoundException(email);
}
}

public UaaUser updateUser(String userId, UaaUser user) throws UsernameNotFoundException {
if (user.getId().equals(userId)) {
this.user = user;
Expand Down

0 comments on commit bac30e2

Please sign in to comment.