/**
* =============================================================================
*
* ORCID (R) Open Source
* http://orcid.org
*
* Copyright (c) 2012-2014 ORCID, Inc.
* Licensed under an MIT-Style License (MIT)
* http://orcid.org/open-source-license
*
* This copyright and license information (including a link to the full license)
* shall be included in its entirety in all copies or substantial portion of
* the software.
*
* =============================================================================
*/
package org.orcid.core.manager;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import javax.annotation.Resource;
import org.apache.commons.io.IOUtils;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.orcid.core.oauth.OrcidOauth2TokenDetailService;
import org.orcid.core.utils.JsonUtils;
import org.orcid.persistence.dao.UserConnectionDao;
import org.orcid.persistence.jpa.entities.ClientDetailsEntity;
import org.orcid.persistence.jpa.entities.UserconnectionEntity;
import org.orcid.pojo.HeaderCheckResult;
import org.orcid.pojo.HeaderMismatch;
import org.orcid.test.OrcidJUnit4ClassRunner;
import org.orcid.test.TargetProxyHelper;
import org.springframework.test.context.ContextConfiguration;
@RunWith(OrcidJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "classpath:orcid-core-context.xml" })
public class InstitutionalSignInManagerTest {
private final String userOrcid = "0000-0000-0000-0001";
private final String clientId = "APP-00000000001";
@Mock
private UserConnectionDao mock_userConnectionDao;
@Mock
private ClientDetailsEntityCacheManager mock_clientDetailsEntityCacheManager;
@Mock
private NotificationManager mock_notificationManager;
@Mock
private OrcidOauth2TokenDetailService mock_orcidOauth2TokenDetailService;
@Resource
private UserConnectionDao userConnectionDao;
@Resource
private ClientDetailsEntityCacheManager clientDetailsEntityCacheManager;
@Resource
private NotificationManager notificationManager;
@Resource
private OrcidOauth2TokenDetailService orcidOauth2TokenDetailService;
@Resource
private InstitutionalSignInManager institutionalSignInManager;
@Before
public void before() {
MockitoAnnotations.initMocks(this);
TargetProxyHelper.injectIntoProxy(institutionalSignInManager, "userConnectionDao", mock_userConnectionDao);
TargetProxyHelper.injectIntoProxy(institutionalSignInManager, "clientDetailsEntityCacheManager", mock_clientDetailsEntityCacheManager);
TargetProxyHelper.injectIntoProxy(institutionalSignInManager, "notificationManager", mock_notificationManager);
TargetProxyHelper.injectIntoProxy(institutionalSignInManager, "orcidOauth2TokenDetailService", mock_orcidOauth2TokenDetailService);
}
@After
public void after() {
// Rollback to the original beans
TargetProxyHelper.injectIntoProxy(institutionalSignInManager, "userConnectionDao", userConnectionDao);
TargetProxyHelper.injectIntoProxy(institutionalSignInManager, "clientDetailsEntityCacheManager", clientDetailsEntityCacheManager);
TargetProxyHelper.injectIntoProxy(institutionalSignInManager, "notificationManager", notificationManager);
TargetProxyHelper.injectIntoProxy(institutionalSignInManager, "orcidOauth2TokenDetailService", orcidOauth2TokenDetailService);
}
@Test
public void testCreateUserConnectionAndNotify() throws UnsupportedEncodingException {
ClientDetailsEntity testClient = new ClientDetailsEntity(clientId);
when(mock_userConnectionDao.findByProviderIdAndProviderUserIdAndIdType(anyString(), anyString(), anyString())).thenReturn(null);
when(mock_clientDetailsEntityCacheManager.retrieveByIdP(anyString())).thenReturn(testClient);
when(mock_orcidOauth2TokenDetailService.doesClientKnowUser(anyString(), anyString())).thenReturn(false);
institutionalSignInManager.createUserConnectionAndNotify("idType", "remoteUserId", "displayName", "providerId", userOrcid,
Collections.<String, String> emptyMap());
verify(mock_userConnectionDao, times(1)).persist(any());
verify(mock_notificationManager, times(1)).sendAcknowledgeMessage(userOrcid, clientId);
}
@Test
public void testDontSendNotificationIfClientKnowUser() throws UnsupportedEncodingException {
ClientDetailsEntity testClient = new ClientDetailsEntity(clientId);
when(mock_userConnectionDao.findByProviderIdAndProviderUserIdAndIdType(anyString(), anyString(), anyString())).thenReturn(null);
when(mock_clientDetailsEntityCacheManager.retrieveByIdP(anyString())).thenReturn(testClient);
when(mock_orcidOauth2TokenDetailService.doesClientKnowUser(anyString(), anyString())).thenReturn(true);
institutionalSignInManager.createUserConnectionAndNotify("idType", "remoteUserId", "displayName", "providerId", userOrcid,
Collections.<String, String> emptyMap());
verify(mock_userConnectionDao, times(1)).persist(any());
verify(mock_notificationManager, never()).sendAcknowledgeMessage(userOrcid, clientId);
}
@Test
public void testDontSendNotificationIfIdPNotLinkedToClient() throws UnsupportedEncodingException {
when(mock_userConnectionDao.findByProviderIdAndProviderUserIdAndIdType(anyString(), anyString(), anyString())).thenReturn(null);
when(mock_clientDetailsEntityCacheManager.retrieveByIdP(anyString())).thenThrow(new IllegalArgumentException());
when(mock_orcidOauth2TokenDetailService.doesClientKnowUser(anyString(), anyString())).thenReturn(false);
institutionalSignInManager.createUserConnectionAndNotify("idType", "remoteUserId", "displayName", "providerId", userOrcid,
Collections.<String, String> emptyMap());
verify(mock_userConnectionDao, times(1)).persist(any());
verify(mock_notificationManager, never()).sendAcknowledgeMessage(userOrcid, clientId);
}
@Test
public void testDontPersistIfUserConnectionAlreadyExists() throws UnsupportedEncodingException {
ClientDetailsEntity testClient = new ClientDetailsEntity(clientId);
when(mock_userConnectionDao.findByProviderIdAndProviderUserIdAndIdType(anyString(), anyString(), anyString())).thenReturn(new UserconnectionEntity());
when(mock_clientDetailsEntityCacheManager.retrieveByIdP(anyString())).thenReturn(testClient);
when(mock_orcidOauth2TokenDetailService.doesClientKnowUser(anyString(), anyString())).thenReturn(false);
institutionalSignInManager.createUserConnectionAndNotify("idType", "remoteUserId", "displayName", "providerId", userOrcid,
Collections.<String, String> emptyMap());
verify(mock_userConnectionDao, never()).persist(any());
verify(mock_notificationManager, times(1)).sendAcknowledgeMessage(userOrcid, clientId);
}
@Test
public void testDontPersistAndDontNotify() throws UnsupportedEncodingException {
when(mock_userConnectionDao.findByProviderIdAndProviderUserIdAndIdType(anyString(), anyString(), anyString())).thenReturn(new UserconnectionEntity());
when(mock_clientDetailsEntityCacheManager.retrieveByIdP(anyString())).thenThrow(new IllegalArgumentException());
when(mock_orcidOauth2TokenDetailService.doesClientKnowUser(anyString(), anyString())).thenReturn(true);
institutionalSignInManager.createUserConnectionAndNotify("idType", "remoteUserId", "displayName", "providerId", userOrcid,
Collections.<String, String> emptyMap());
verify(mock_userConnectionDao, never()).persist(any());
verify(mock_notificationManager, never()).sendAcknowledgeMessage(userOrcid, clientId);
}
@Test
public void testCheckHeaders() throws IOException {
@SuppressWarnings("unchecked")
Map<String, String> originalHeaders = JsonUtils.readObjectFromJsonString(IOUtils.toString(getClass().getResource("shibboleth_headers_original.json")), Map.class);
Map<String, String> currentHeaders = new HashMap<>(originalHeaders);
// When all headers are the same
HeaderCheckResult result = institutionalSignInManager.checkHeaders(originalHeaders, currentHeaders);
assertTrue(result.isSuccess());
assertEquals(0, result.getMismatches().size());
// When eppn is different
currentHeaders.put("eppn", "someoneelse@testshib.org");
result = institutionalSignInManager.checkHeaders(originalHeaders, currentHeaders);
assertFalse(result.isSuccess());
assertEquals(1, result.getMismatches().size());
HeaderMismatch mismatch = result.getMismatches().get(0);
assertEquals("eppn", mismatch.getHeaderName());
assertEquals("myself@testshib.org", mismatch.getOriginalValue());
assertEquals("someoneelse@testshib.org", mismatch.getCurrentValue());
// When eppn was originally there, but is not now
currentHeaders.remove("eppn");
result = institutionalSignInManager.checkHeaders(originalHeaders, currentHeaders);
assertTrue(result.isSuccess());
assertEquals(0, result.getMismatches().size());
// When eppn is duplicated but unchanged
currentHeaders.put("eppn", "myself@testshib.org;myself@testshib.org");
result = institutionalSignInManager.checkHeaders(originalHeaders, currentHeaders);
assertTrue(result.isSuccess());
assertEquals(0, result.getMismatches().size());
// When eppn is duplicated and changed
currentHeaders.put("eppn", "someoneelse@testshib.org;someoneelse@testshib.org");
result = institutionalSignInManager.checkHeaders(originalHeaders, currentHeaders);
assertFalse(result.isSuccess());
assertEquals(1, result.getMismatches().size());
mismatch = result.getMismatches().get(0);
assertEquals("eppn", mismatch.getHeaderName());
assertEquals("myself@testshib.org", mismatch.getOriginalValue());
assertEquals("someoneelse@testshib.org;someoneelse@testshib.org", mismatch.getCurrentValue());
// When eppn is duplicated and one of values changed
currentHeaders.put("eppn", "myself@testshib.org;someoneelse@testshib.org");
result = institutionalSignInManager.checkHeaders(originalHeaders, currentHeaders);
assertFalse(result.isSuccess());
assertEquals(1, result.getMismatches().size());
mismatch = result.getMismatches().get(0);
assertEquals("eppn", mismatch.getHeaderName());
assertEquals("myself@testshib.org", mismatch.getOriginalValue());
assertEquals("myself@testshib.org;someoneelse@testshib.org", mismatch.getCurrentValue());
}
}