package org.synyx.urlaubsverwaltung.security;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Matchers;
import org.mockito.Mockito;
import org.springframework.ldap.core.DirContextOperations;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.DisabledException;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.synyx.urlaubsverwaltung.core.person.Person;
import org.synyx.urlaubsverwaltung.core.person.PersonService;
import org.synyx.urlaubsverwaltung.core.person.Role;
import org.synyx.urlaubsverwaltung.test.TestDataCreator;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Optional;
import javax.naming.Name;
import javax.naming.NamingException;
/**
* Unit test for {@link org.synyx.urlaubsverwaltung.security.PersonContextMapper}.
*
* @author Aljona Murygina - murygina@synyx.de
*/
public class PersonContextMapperTest {
private PersonContextMapper personContextMapper;
private PersonService personService;
private LdapSyncService ldapSyncService;
private LdapUserMapper ldapUserMapper;
private DirContextOperations context;
@Before
public void setUp() {
personService = Mockito.mock(PersonService.class);
ldapSyncService = Mockito.mock(LdapSyncService.class);
ldapUserMapper = Mockito.mock(LdapUserMapper.class);
personContextMapper = new PersonContextMapper(personService, ldapSyncService, ldapUserMapper);
context = Mockito.mock(DirContextOperations.class);
Mockito.when(context.getDn()).thenReturn(Mockito.mock(Name.class));
Mockito.when(context.getStringAttributes("cn")).thenReturn(new String[] { "First", "Last" });
Mockito.when(context.getStringAttribute(Mockito.anyString())).thenReturn("Foo");
}
@Test(expected = IllegalArgumentException.class)
public void ensureThrowsIfTryingToGetAuthoritiesForNullPerson() {
personContextMapper.getGrantedAuthorities(null);
}
@Test(expected = IllegalStateException.class)
public void ensureThrowsIfTryingToGetAuthoritiesOfPersonWithNoRoles() {
Person person = TestDataCreator.createPerson();
person.setPermissions(Collections.emptyList());
personContextMapper.getGrantedAuthorities(person);
}
@Test
public void ensureReturnsCorrectListOfAuthoritiesUsingTheRolesOfTheGivenPerson() {
Person person = TestDataCreator.createPerson();
person.setPermissions(Arrays.asList(Role.USER, Role.BOSS));
Collection<GrantedAuthority> authorities = personContextMapper.getGrantedAuthorities(person);
Assert.assertEquals("Wrong number of authorities", 2, authorities.size());
Assert.assertTrue("No authority for user role found",
SecurityTestUtil.authorityForRoleExists(authorities, Role.USER));
Assert.assertTrue("No authority for boss role found",
SecurityTestUtil.authorityForRoleExists(authorities, Role.BOSS));
}
@Test
public void ensureCreatesPersonIfPersonDoesNotExist() throws NamingException,
UnsupportedMemberAffiliationException {
Mockito.when(ldapUserMapper.mapFromContext(Mockito.eq(context)))
.thenReturn(new LdapUser("murygina", Optional.of("Aljona"), Optional.of("Murygina"),
Optional.of("murygina@synyx.de")));
Mockito.when(personService.getPersonByLogin(Mockito.anyString())).thenReturn(Optional.<Person>empty());
Mockito.when(ldapSyncService.createPerson(Mockito.anyString(), Matchers.<Optional<String>>any(),
Matchers.<Optional<String>>any(), Matchers.<Optional<String>>any()))
.thenReturn(TestDataCreator.createPerson());
personContextMapper.mapUserFromContext(context, "murygina", null);
Mockito.verify(ldapUserMapper).mapFromContext(context);
Mockito.verify(ldapSyncService)
.createPerson(Mockito.eq("murygina"), Mockito.eq(Optional.of("Aljona")),
Mockito.eq(Optional.of("Murygina")), Mockito.eq(Optional.of("murygina@synyx.de")));
}
@Test
public void ensureSyncsPersonDataUsingLDAPAttributes() throws NamingException,
UnsupportedMemberAffiliationException {
Person person = TestDataCreator.createPerson();
person.setPermissions(Collections.singletonList(Role.USER));
Mockito.when(ldapUserMapper.mapFromContext(Mockito.eq(context)))
.thenReturn(new LdapUser("murygina", Optional.of("Aljona"), Optional.of("Murygina"),
Optional.of("murygina@synyx.de")));
Mockito.when(personService.getPersonByLogin(Mockito.anyString())).thenReturn(Optional.of(person));
Mockito.when(ldapSyncService.syncPerson(Mockito.any(Person.class), Matchers.<Optional<String>>any(),
Matchers.<Optional<String>>any(), Matchers.<Optional<String>>any()))
.thenReturn(person);
personContextMapper.mapUserFromContext(context, "murygina", null);
Mockito.verify(ldapUserMapper).mapFromContext(context);
Mockito.verify(ldapSyncService)
.syncPerson(Mockito.eq(person), Mockito.eq(Optional.of("Aljona")), Mockito.eq(Optional.of("Murygina")),
Mockito.eq(Optional.of("murygina@synyx.de")));
}
@Test
public void ensureUsernameIsBasedOnLdapUsername() throws NamingException, UnsupportedMemberAffiliationException {
String userIdentifier = "mgroehning";
String userNameSignedInWith = "mgroehning@simpsons.com";
Mockito.when(ldapUserMapper.mapFromContext(Mockito.eq(context)))
.thenReturn(new LdapUser("mgroehning", Optional.<String>empty(), Optional.<String>empty(),
Optional.<String>empty()));
Mockito.when(personService.getPersonByLogin(Mockito.anyString())).thenReturn(Optional.<Person>empty());
Mockito.when(ldapSyncService.createPerson(Mockito.anyString(), Matchers.<Optional<String>>any(),
Matchers.<Optional<String>>any(), Matchers.<Optional<String>>any()))
.thenReturn(TestDataCreator.createPerson());
UserDetails userDetails = personContextMapper.mapUserFromContext(context, userNameSignedInWith, null);
Assert.assertNotNull("Username should be set", userDetails.getUsername());
Assert.assertEquals("Wrong username", userIdentifier, userDetails.getUsername());
}
@Test(expected = DisabledException.class)
public void ensureLoginIsNotPossibleIfUserIsDeactivated() throws UnsupportedMemberAffiliationException,
NamingException {
Person person = TestDataCreator.createPerson();
person.setPermissions(Collections.singletonList(Role.INACTIVE));
Mockito.when(personService.getPersonByLogin(Mockito.anyString())).thenReturn(Optional.of(person));
Mockito.when(ldapUserMapper.mapFromContext(Mockito.eq(context)))
.thenReturn(new LdapUser(person.getLoginName(), Optional.of(person.getFirstName()),
Optional.of(person.getLastName()), Optional.of(person.getEmail())));
Mockito.when(ldapSyncService.syncPerson(Mockito.any(Person.class), Matchers.<Optional<String>>any(),
Matchers.<Optional<String>>any(), Matchers.<Optional<String>>any()))
.thenReturn(person);
personContextMapper.mapUserFromContext(context, person.getLoginName(), null);
}
@Test(expected = BadCredentialsException.class)
public void ensureLoginIsNotPossibleIfLdapUserCanNotBeCreatedBecauseOfInvalidUserIdentifier()
throws NamingException, UnsupportedMemberAffiliationException {
Mockito.when(ldapUserMapper.mapFromContext(Mockito.eq(context)))
.thenThrow(new InvalidSecurityConfigurationException("Bad!"));
personContextMapper.mapUserFromContext(context, "username", null);
}
@Test(expected = BadCredentialsException.class)
public void ensureLoginIsNotPossibleIfLdapUserHasNotSupportedMemberOfAttribute() throws NamingException,
UnsupportedMemberAffiliationException {
Mockito.when(ldapUserMapper.mapFromContext(Mockito.eq(context)))
.thenThrow(new UnsupportedMemberAffiliationException("Bad!"));
personContextMapper.mapUserFromContext(context, "username", null);
}
@Test
public void ensureAuthoritiesAreBasedOnRolesOfTheSignedInPerson() throws NamingException,
UnsupportedMemberAffiliationException {
Person person = TestDataCreator.createPerson("username");
person.setPermissions(Arrays.asList(Role.USER, Role.BOSS));
Mockito.when(ldapUserMapper.mapFromContext(Mockito.eq(context)))
.thenReturn(new LdapUser("username", Optional.<String>empty(), Optional.<String>empty(),
Optional.<String>empty()));
Mockito.when(personService.getPersonByLogin(Mockito.anyString())).thenReturn(Optional.of(person));
Mockito.when(ldapSyncService.syncPerson(Mockito.any(Person.class), Matchers.<Optional<String>>any(),
Matchers.<Optional<String>>any(), Matchers.<Optional<String>>any()))
.thenReturn(person);
UserDetails userDetails = personContextMapper.mapUserFromContext(context, "username", null);
Collection<? extends GrantedAuthority> authorities = userDetails.getAuthorities();
Assert.assertEquals("Wrong number of authorities", 2, authorities.size());
Assert.assertTrue("Missing authority for user role",
SecurityTestUtil.authorityForRoleExists(authorities, Role.USER));
Assert.assertTrue("Missing authority for boss role",
SecurityTestUtil.authorityForRoleExists(authorities, Role.BOSS));
}
@Test
public void ensureAddsOfficeRoleToSignedInUserIfNoUserWithOfficeRoleExistsYet() throws NamingException,
UnsupportedMemberAffiliationException {
Person person = TestDataCreator.createPerson("username");
person.setPermissions(Collections.singletonList(Role.USER));
Mockito.when(ldapUserMapper.mapFromContext(Mockito.eq(context)))
.thenReturn(new LdapUser("username", Optional.<String>empty(), Optional.<String>empty(),
Optional.<String>empty()));
Mockito.when(personService.getPersonByLogin(Mockito.anyString())).thenReturn(Optional.of(person));
Mockito.when(personService.getPersonsByRole(Role.OFFICE)).thenReturn(Collections.emptyList());
Mockito.when(ldapSyncService.syncPerson(Mockito.any(Person.class), Matchers.<Optional<String>>any(),
Matchers.<Optional<String>>any(), Matchers.<Optional<String>>any()))
.thenReturn(person);
personContextMapper.mapUserFromContext(context, "username", null);
Mockito.verify(personService).getPersonsByRole(Role.OFFICE);
Mockito.verify(ldapSyncService).appointPersonAsOfficeUser(person);
}
}