gt:             String getAccessTokenFromTokens() {
context: /*******************************************************************************
   * Copyright (c) 2016, 2018 IBM Corporation and others.
   * All rights reserved. This program and the accompanying materials
   * are made available under the terms of the Eclipse Public License v1.0
   * which accompanies this distribution, and is available at
   * http://www.eclipse.org/legal/epl-v10.html
   *
   * Contributors:
   *     IBM Corporation - initial API and implementation
   *******************************************************************************/
  package com.ibm.ws.security.social.tai;
  
  import static org.junit.Assert.assertEquals;
  import static org.junit.Assert.assertNotNull;
  import static org.junit.Assert.assertNull;
  import static org.junit.Assert.assertTrue;
  import static org.junit.Assert.fail;
  
  import java.util.HashMap;
  import java.util.Map;
  import java.util.regex.Pattern;
  
  import javax.net.ssl.SSLSocketFactory;
  
  import org.jmock.Expectations;
  import org.junit.After;
  import org.junit.AfterClass;
  import org.junit.Before;
  import org.junit.BeforeClass;
  import org.junit.Rule;
  import org.junit.Test;
  import org.junit.rules.TestName;
  
  import com.ibm.websphere.security.jwt.JwtToken;
  import com.ibm.ws.common.internal.encoder.Base64Coder;
  import com.ibm.ws.security.common.random.RandomUtils;
  import com.ibm.ws.security.social.SocialLoginConfig;
  import com.ibm.ws.security.social.UserApiConfig;
  import com.ibm.ws.security.social.error.SocialLoginException;
  import com.ibm.ws.security.social.internal.utils.ClientConstants;
  import com.ibm.ws.security.social.internal.utils.OAuthClientUtil;
  import com.ibm.ws.security.social.test.CommonTestClass;
  
  import test.common.SharedOutputManager;
  
  public class AuthorizationCodeAuthenticatorTest extends CommonTestClass {
  
      private static SharedOutputManager outputMgr = SharedOutputManager.getInstance().trace("com.ibm.ws.security.social.*=all");
  
      private static final String AUTHZ_CODE = "1234567890";
      private static String ACCESS_TOKEN = "EAANQIE2J5nMBAErWBIFfkmu9r6yQeGoIMg39mHRJrZA7L0jbiD7GEpLSZBm96tgqvvlbQI3UIgQXSJaO6sRJGaFEZCwn5kolWgSjs5q71rrNg0GdbHk5yxrtsZAWsZBv3XV1xFmJ4reZBKA6sx5PqQJejg5RtTWKPg4jJoP0zk1AZDZD";
      private static String REFRESH_TOKEN = "67890";
      private static long EXPIRES_IN = 5177064;
      // IdToken with claims {"at_hash":"0HbzhW49bhEP2b3SVHfeGg","sub":"user1","realmName":"OpBasicRealm","uniqueSecurityName":"user1","iss":"https://localhost:8020/oidc/endpoint/OP","nonce":"v1zg5OZ9vXP5h0lEiYs1","aud":"rp","exp":1455909058,"iat":1455901858}
      private static final String ID_TOKEN = "eyJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwczovL2xvY2FsaG9zdDo4MDIwL29pZGMvZW5kcG9pbnQvT1AiLCJub25jZSI6InYxemc1T1o5dlhQNWgwbEVpWXMxIiwiaWF0IjoxNDU1OTAxODU4LCJzdWIiOiJ1c2VyMSIsImV4cCI6MTQ1NTkwOTA1OCwiYXVkIjoicnAiLCJyZWFsbU5hbWUiOiJPcEJhc2ljUmVhbG0iLCJ1bmlxdWVTZWN1cml0eU5hbWUiOiJ1c2VyMSIsImF0X2hhc2giOiIwSGJ6aFc0OWJoRVAyYjNTVkhmZUdnIn0.VJNknPRe0BhzfMA4MpQIEeVczaHYiMzPiBYejp72zIs";
  
      public interface MockInterface {
          void createSslSocketFactory() throws SocialLoginException;
  
          void getTokensFromTokenEndpoint() throws SocialLoginException;
  
          Map<String, Object> getTokensUsingAuthzCode() throws SocialLoginException;
  
          void createJwtUserApiResponseAndIssuedJwtWithAppropriateToken() throws SocialLoginException;
  
          String getIdTokenFromTokens();
  
          void createJwtUserApiResponseAndIssuedJwtFromUserApi() throws SocialLoginException;
  
          String getAccessTokenFromTokens();
  
          void createUserApiResponseFromAccessToken() throws SocialLoginException;
  
          void createIssuedJwtFromUserApiResponse() throws SocialLoginException;
  
          void createJwtUserApiResponseAndIssuedJwtFromIdToken() throws SocialLoginException;
  
          void createJwtAndIssuedJwtFromIdToken() throws SocialLoginException;
  
          void createJwtFromIdToken() throws SocialLoginException;
  
          void createIssuedJwtFromIdToken() throws Exception;
  
          void createUserApiResponseFromIdToken();
      }
  
      final MockInterface mockInterface = mockery.mock(MockInterface.class);
  
      final SSLSocketFactory sslSocketFactory = mockery.mock(SSLSocketFactory.class);
      final JwtToken jwtToken = mockery.mock(JwtToken.class, "jwtToken");
      final OAuthClientUtil clientUtil = mockery.mock(OAuthClientUtil.class);
      final SocialLoginConfig config = mockery.mock(SocialLoginConfig.class, "mockSocialLoginConfig");
      final TAIWebUtils taiWebUtils = mockery.mock(TAIWebUtils.class);
      final TAIJwtUtils taiJwtUtils = mockery.mock(TAIJwtUtils.class);
      final UserApiConfig userApiConfig = mockery.mock(UserApiConfig.class);
  
      AuthorizationCodeAuthenticator authenticator = null;
  
      @Rule
      public final TestName testName = new TestName();
  
      @BeforeClass
      public static void setUpBeforeClass() throws Exception {
          outputMgr.captureStreams();
      }
  
      @Before
      public void setUp() throws Exception {
          System.out.println("Entering test: " + testName.getMethodName());
          authenticator = new AuthorizationCodeAuthenticator(request, response, AUTHZ_CODE, config);
          mockProtectedClassMembers(authenticator);
      }
  
      @After
      public void tearDown() throws Exception {
          System.out.println("Exiting test: " + testName.getMethodName());
          outputMgr.resetStreams();
          mockery.assertIsSatisfied();
      }
  
      @AfterClass
      public static void tearDownAfterClass() throws Exception {
          outputMgr.dumpStreams();
          outputMgr.restoreStreams();
      }
  
      private void mockProtectedClassMembers(AuthorizationCodeAuthenticator authenticator) {
          authenticator.clientUtil = clientUtil;
          authenticator.taiWebUtils = taiWebUtils;
          authenticator.taiJwtUtils = taiJwtUtils;
      }
  
      /****************************************** generateJwtAndTokenInformation ******************************************/
  
      @Test
      public void test_generateJwtAndTokenInformation_createSslSocketFactoryThrowsException() throws Exception {
          authenticator = new AuthorizationCodeAuthenticator(request, response, AUTHZ_CODE, config) {
              @Override
              void createSslSocketFactory() throws SocialLoginException {
                  mockInterface.createSslSocketFactory();
              }
          };
          mockProtectedClassMembers(authenticator);
          try {
              mockery.checking(new Expectations() {
                  {
                      one(mockInterface).createSslSocketFactory();
                      will(throwException(new SocialLoginException(defaultExceptionMsg, null, null)));
                  }
              });
  
              try {
                  authenticator.generateJwtAndTokenInformation();
                  fail("Should have thrown exception but did not.");
              } catch (SocialLoginException e) {
                  verifyException(e, Pattern.quote(defaultExceptionMsg));
              }
  
              // generateJwtAndTokenInformation() does not emit its own message when one of the methods it calls throws an exception
              verifyNoLogMessage(outputMgr, MSG_BASE);
  
          } catch (Throwable t) {
              outputMgr.failWithThrowable(testName.getMethodName(), t);
          }
      }
  
      @Test
      public void test_generateJwtAndTokenInformation_getTokensFromTokenEndpointThrowsException() throws Exception {
          authenticator = new AuthorizationCodeAuthenticator(request, response, AUTHZ_CODE, config) {
              @Override
              void createSslSocketFactory() throws SocialLoginException {
                  mockInterface.createSslSocketFactory();
              }
  
              @Override
              void getTokensFromTokenEndpoint() throws SocialLoginException {
                  mockInterface.getTokensFromTokenEndpoint();
              }
          };
          mockProtectedClassMembers(authenticator);
          try {
              mockery.checking(new Expectations() {
                  {
                      one(mockInterface).createSslSocketFactory();
                      one(mockInterface).getTokensFromTokenEndpoint();
                      will(throwException(new SocialLoginException(defaultExceptionMsg, null, null)));
                  }
              });
  
              try {
                  authenticator.generateJwtAndTokenInformation();
                  fail("Should have thrown exception but did not.");
              } catch (SocialLoginException e) {
                  verifyException(e, Pattern.quote(defaultExceptionMsg));
              }
  
              // generateJwtAndTokenInformation() does not emit its own message when one of the methods it calls throws an exception
              verifyNoLogMessage(outputMgr, MSG_BASE);
  
          } catch (Throwable t) {
              outputMgr.failWithThrowable(testName.getMethodName(), t);
          }
      }
  
      @Test
      public void test_generateJwtAndTokenInformation_createJwtWithAppropriateTokenThrowsException() throws Exception {
          authenticator = new AuthorizationCodeAuthenticator(request, response, AUTHZ_CODE, config) {
              @Override
              void createSslSocketFactory() throws SocialLoginException {
                  mockInterface.createSslSocketFactory();
              }
  
              @Override
              void getTokensFromTokenEndpoint() throws SocialLoginException {
                  mockInterface.getTokensFromTokenEndpoint();
              }
  
              @Override
              public void createJwtUserApiResponseAndIssuedJwtWithAppropriateToken() throws SocialLoginException {
                  mockInterface.createJwtUserApiResponseAndIssuedJwtWithAppropriateToken();
              }
          };
          mockProtectedClassMembers(authenticator);
          try {
              mockery.checking(new Expectations() {
                  {
                      one(mockInterface).createSslSocketFactory();
                      one(mockInterface).getTokensFromTokenEndpoint();
                      one(mockInterface).createJwtUserApiResponseAndIssuedJwtWithAppropriateToken();
                      will(throwException(new SocialLoginException(defaultExceptionMsg, null, null)));
                  }
              });
  
              try {
                  authenticator.generateJwtAndTokenInformation();
                  fail("Should have thrown exception but did not.");
              } catch (SocialLoginException e) {
                  verifyException(e, Pattern.quote(defaultExceptionMsg));
              }
  
              // generateJwtAndTokenInformation() does not emit its own message when one of the methods it calls throws an exception
              verifyNoLogMessage(outputMgr, MSG_BASE);
  
          } catch (Throwable t) {
              outputMgr.failWithThrowable(testName.getMethodName(), t);
          }
      }
  
      @Test
      public void test_generateJwtAndTokenInformation_successful() throws Exception {
          authenticator = new AuthorizationCodeAuthenticator(request, response, AUTHZ_CODE, config) {
              @Override
              void createSslSocketFactory() throws SocialLoginException {
                  mockInterface.createSslSocketFactory();
              }
  
              @Override
              void getTokensFromTokenEndpoint() throws SocialLoginException {
                  mockInterface.getTokensFromTokenEndpoint();
              }
  
              @Override
              public void createJwtUserApiResponseAndIssuedJwtWithAppropriateToken() throws SocialLoginException {
                  mockInterface.createJwtUserApiResponseAndIssuedJwtWithAppropriateToken();
              }
          };
          mockProtectedClassMembers(authenticator);
          try {
              mockery.checking(new Expectations() {
                  {
                      one(mockInterface).createSslSocketFactory();
                      one(mockInterface).getTokensFromTokenEndpoint();
                      one(mockInterface).createJwtUserApiResponseAndIssuedJwtWithAppropriateToken();
                  }
              });
  
              authenticator.generateJwtAndTokenInformation();
  
              verifyNoLogMessage(outputMgr, MSG_BASE);
  
          } catch (Throwable t) {
              outputMgr.failWithThrowable(testName.getMethodName(), t);
          }
      }
  
      /****************************************** createSslSocketFactory ******************************************/
  
      @Test
      public void test_createSslSocketFactory_throwsException() throws Exception {
          try {
              mockery.checking(new Expectations() {
                  {
                      one(config).getSSLSocketFactory();
                      will(throwException(new SocialLoginException(defaultExceptionMsg, null, null)));
                      one(config).getUniqueId();
                      will(returnValue(uniqueId));
                  }
              });
  
              final String exceptionAndLogMessage = CWWKS5450E_AUTH_CODE_ERROR_SSL_CONTEXT + ".+\\[" + uniqueId + "\\].+" + Pattern.quote(defaultExceptionMsg);
              try {
                  authenticator.createSslSocketFactory();
                  fail("Should have thrown exception but did not.");
              } catch (SocialLoginException e) {
                  verifyException(e, exceptionAndLogMessage);
              }
  
              verifyLogMessage(outputMgr, exceptionAndLogMessage);
  
          } catch (Throwable t) {
              outputMgr.failWithThrowable(testName.getMethodName(), t);
          }
      }
  
      @Test
      public void test_createSslSocketFactory_successful() throws Exception {
          try {
              mockery.checking(new Expectations() {
                  {
                      one(config).getSSLSocketFactory();
                      will(returnValue(sslSocketFactory));
                  }
              });
  
              authenticator.createSslSocketFactory();
  
              assertNotNull("SSL socket factory should not have been null but was.", authenticator.sslSocketFactory);
  
              verifyNoLogMessage(outputMgr, MSG_BASE);
  
          } catch (Throwable t) {
              outputMgr.failWithThrowable(testName.getMethodName(), t);
          }
      }
  
      /****************************************** getTokensFromTokenEndpoint ******************************************/
  
      @Test
      public void test_getTokensFromTokenEndpoint_exceptionThrown() throws Exception {
          authenticator = new AuthorizationCodeAuthenticator(request, response, AUTHZ_CODE, config) {
              @Override
              Map<String, Object> getTokensUsingAuthzCode() throws SocialLoginException {
                  return mockInterface.getTokensUsingAuthzCode();
              }
          };
          mockProtectedClassMembers(authenticator);
          try {
              mockery.checking(new Expectations() {
                  {
                      one(mockInterface).getTokensUsingAuthzCode();
                      will(throwException(new SocialLoginException(defaultExceptionMsg, null, null)));
                      one(config).getUniqueId();
                      will(returnValue(uniqueId));
                  }
              });
  
              try {
                  authenticator.getTokensFromTokenEndpoint();
                  fail("Should have thrown exception but did not.");
              } catch (SocialLoginException e) {
                  verifyException(e, Pattern.quote(defaultExceptionMsg));
              }
  
              verifyLogMessage(outputMgr, CWWKS5451E_AUTH_CODE_ERROR_GETTING_TOKENS + ".+\\[" + uniqueId + "\\].+" + Pattern.quote(defaultExceptionMsg));
  
          } catch (Throwable t) {
              outputMgr.failWithThrowable(testName.getMethodName(), t);
          }
      }
  
      @Test
      public void test_getTokensFromTokenEndpoint_nullTokens() throws Exception {
          authenticator = new AuthorizationCodeAuthenticator(request, response, AUTHZ_CODE, config) {
              @Override
              Map<String, Object> getTokensUsingAuthzCode() throws SocialLoginException {
                  return mockInterface.getTokensUsingAuthzCode();
              }
          };
          mockProtectedClassMembers(authenticator);
          try {
              mockery.checking(new Expectations() {
                  {
                      one(mockInterface).getTokensUsingAuthzCode();
                      will(returnValue(null));
                  }
              });
  
              authenticator.getTokensFromTokenEndpoint();
  
              assertNull("Tokens should have been null but were: " + authenticator.getTokens(), authenticator.getTokens());
  
              verifyNoLogMessage(outputMgr, MSG_BASE);
  
          } catch (Throwable t) {
              outputMgr.failWithThrowable(testName.getMethodName(), t);
          }
      }
  
      @Test
      public void test_getTokensFromTokenEndpoint_nonEmptyTokens() throws Exception {
          authenticator = new AuthorizationCodeAuthenticator(request, response, AUTHZ_CODE, config) {
              @Override
              Map<String, Object> getTokensUsingAuthzCode() throws SocialLoginException {
                  return mockInterface.getTokensUsingAuthzCode();
              }
          };
          mockProtectedClassMembers(authenticator);
          final Map<String, Object> tokens = createTokens(ACCESS_TOKEN, REFRESH_TOKEN, ID_TOKEN, EXPIRES_IN);
          try {
              mockery.checking(new Expectations() {
                  {
                      one(mockInterface).getTokensUsingAuthzCode();
                      will(returnValue(tokens));
                  }
              });
  
              authenticator.getTokensFromTokenEndpoint();
  
              assertEquals("Token map did not match expected result.", tokens, authenticator.getTokens());
  
              verifyNoLogMessage(outputMgr, MSG_BASE);
  
          } catch (Throwable t) {
              outputMgr.failWithThrowable(testName.getMethodName(), t);
          }
      }
  
      /****************************************** getTokensUsingAuthzCode ******************************************/
  
      @Test
      public void test_getTokensUsingAuthzCode_throwsException() throws Exception {
          try {
              mockery.checking(new Expectations() {
                  {
                      one(config).getTokenEndpoint();
                      one(config).getClientId();
                      one(config).getClientSecret();
                      one(config).getTokenEndpointAuthMethod();
                      one(config).getUseSystemPropertiesForHttpClientConnections();
                      one(config).getResource();
                      one(taiWebUtils).getRedirectUrl(request, config);
                      one(clientUtil).getTokensFromAuthzCode(with(any(String.class)), with(any(String.class)), with(any(String.class)), with(any(String.class)), with(any(String.class)),
                              with(any(String.class)), with(any(SSLSocketFactory.class)), with(any(boolean.class)), with(any(String.class)), with(any(String.class)), with(any(Boolean.class)));
                      will(throwException(new SocialLoginException(defaultExceptionMsg, null, null)));
                  }
              });
  
              try {
                  Map<String, Object> result = authenticator.getTokensUsingAuthzCode();
                  fail("Should have thrown exception, but instead got tokens: " + result);
              } catch (SocialLoginException e) {
                  verifyException(e, Pattern.quote(defaultExceptionMsg));
              }
  
              verifyNoLogMessage(outputMgr, MSG_BASE);
  
          } catch (Throwable t) {
              outputMgr.failWithThrowable(testName.getMethodName(), t);
          }
      }
  
      @Test
      public void test_getTokensUsingAuthzCode_nullTokens() throws Exception {
          try {
              mockery.checking(new Expectations() {
                  {
                      one(config).getTokenEndpoint();
                      one(config).getClientId();
                      one(config).getClientSecret();
                      one(config).getTokenEndpointAuthMethod();
                      one(config).getUseSystemPropertiesForHttpClientConnections();
                      one(config).getResource();
                      one(taiWebUtils).getRedirectUrl(request, config);
                      one(clientUtil).getTokensFromAuthzCode(with(any(String.class)), with(any(String.class)), with(any(String.class)), with(any(String.class)), with(any(String.class)),
                              with(any(String.class)), with(any(SSLSocketFactory.class)), with(any(boolean.class)), with(any(String.class)), with(any(String.class)), with(any(Boolean.class)));
                      will(returnValue(null));
                  }
              });
  
              Map<String, Object> result = authenticator.getTokensUsingAuthzCode();
  
              assertNull("Tokens should have been null but were: " + result, result);
  
              verifyNoLogMessage(outputMgr, MSG_BASE);
  
          } catch (Throwable t) {
              outputMgr.failWithThrowable(testName.getMethodName(), t);
          }
      }
  
      @Test
      public void test_getTokensUsingAuthzCode_nonEmptyTokens() throws Exception {
          final Map<String, Object> tokens = createTokens(ACCESS_TOKEN, REFRESH_TOKEN, ID_TOKEN, EXPIRES_IN);
          try {
              mockery.checking(new Expectations() {
                  {
                      one(config).getTokenEndpoint();
                      one(config).getClientId();
                      one(config).getClientSecret();
                      one(config).getTokenEndpointAuthMethod();
                      one(config).getUseSystemPropertiesForHttpClientConnections();
                      one(config).getResource();
                      one(taiWebUtils).getRedirectUrl(request, config);
                      one(clientUtil).getTokensFromAuthzCode(with(any(String.class)), with(any(String.class)), with(any(String.class)), with(any(String.class)), with(any(String.class)),
                              with(any(String.class)), with(any(SSLSocketFactory.class)), with(any(boolean.class)), with(any(String.class)), with(any(String.class)), with(any(Boolean.class)));
                      will(returnValue(tokens));
                  }
              });
  
              Map<String, Object> result = authenticator.getTokensUsingAuthzCode();
  
              assertEquals("Token map did not match expected result.", tokens, result);
  
              verifyNoLogMessage(outputMgr, MSG_BASE);
  
          } catch (Throwable t) {
              outputMgr.failWithThrowable(testName.getMethodName(), t);
          }
      }
  
      /****************************************** createJwtUserApiResponseAndIssuedJwtWithAppropriateToken ******************************************/
  
      @Test
      public void test_createJwtWithAppropriateToken_nullIdToken_exceptionThrown() throws Exception {
          authenticator = new AuthorizationCodeAuthenticator(request, response, AUTHZ_CODE, config) {
              @Override
              String getIdTokenFromTokens() {
                  return mockInterface.getIdTokenFromTokens();
              }
  
              @Override
  