Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

UML-3121 make redirect uri dynamic #2390

Merged
merged 13 commits into from
Nov 3, 2023
Merged
25 changes: 9 additions & 16 deletions .github/workflows/_build-and-push.yml
Original file line number Diff line number Diff line change
Expand Up @@ -146,19 +146,9 @@ jobs:
matrix.run_unit_tests == 'true' &&
(inputs.specific_path == 'all' || inputs.specific_path == matrix.svc_prefix)

- name: ecr login
id: login_ecr
uses: aws-actions/amazon-ecr-login@f8672cc4c5410eabbb9df3d9bb4c7ad01fc4cc3e # [email protected]
with:
registries: 311462405659
if: |
inputs.push_to_ecr == 'true' &&
(inputs.specific_path == 'all' || inputs.specific_path == matrix.svc_prefix)

- name: docker integration and acceptance tests
env:
SVC_PREFIX: ${{ matrix.svc_prefix }}
ECR_REGISTRY: ${{ steps.login_ecr.outputs.registry }}
run: |
if [[ "${SVC_PREFIX}" = "api" ]]; then
docker run -d --rm --name lpa-codes-pact-mock pactfoundation/pact-cli:latest mock-service -p "80" --host "0.0.0.0" \
Expand All @@ -167,15 +157,10 @@ jobs:
--pact-dir /tmp/pacts --consumer use_a_lasting_power_of_attorney --provider api-gateway
docker run -d --rm --name iap-images-mock pactfoundation/pact-cli:latest mock-service -p "80" --host "0.0.0.0" \
--pact-dir /tmp/pacts --consumer use_a_lasting_power_of_attorney --provider iap-api-gateway
docker run -d --rm --name mock-one-login $ECR_REGISTRY/use_an_lpa/mock_onelogin_app

export DOCKER_REMOTE_LPA_PACT_IP="$(docker inspect --format='{{.NetworkSettings.IPAddress}}' lpa-codes-pact-mock)"
export DOCKER_REMOTE_API_PACT_IP="$(docker inspect --format='{{.NetworkSettings.IPAddress}}' api-gateway-pact-mock)"
export DOCKER_REMOTE_IAP_PACT_IP="$(docker inspect --format='{{.NetworkSettings.IPAddress}}' iap-images-mock)"
export DOCKER_REMOTE_MOCK_ONELOGIN_IP="$(docker inspect --format='{{.NetworkSettings.IPAddress}}' mock-one-login)"

curl -XGET $DOCKER_REMOTE_MOCK_ONELOGIN_IP:8080/token
docker logs mock-one-login

docker run -d --name behattests \
--add-host lpa-codes-pact-mock:$DOCKER_REMOTE_LPA_PACT_IP \
Expand All @@ -189,7 +174,6 @@ jobs:
docker stop lpa-codes-pact-mock
docker stop api-gateway-pact-mock
docker stop iap-images-mock
docker stop mock-one-login
elif [[ "${SVC_PREFIX}" = "front" ]]; then
docker run -d --name behattests front-app:latest

Expand Down Expand Up @@ -272,6 +256,15 @@ jobs:
with:
sarif_file: 'trivy-results.sarif'

- name: ecr login
id: login_ecr
uses: aws-actions/amazon-ecr-login@f8672cc4c5410eabbb9df3d9bb4c7ad01fc4cc3e # [email protected]
with:
registries: 311462405659
if: |
inputs.push_to_ecr == 'true' &&
(inputs.specific_path == 'all' || inputs.specific_path == matrix.svc_prefix)

- name: tag and push container
env:
ECR_REGISTRY: ${{ steps.login_ecr.outputs.registry }}
Expand Down
2 changes: 1 addition & 1 deletion docker-compose.dependencies.yml
Original file line number Diff line number Diff line change
Expand Up @@ -109,4 +109,4 @@ services:
environment:
PUBLIC_URL: http://localhost:4013
INTERNAL_URL: http://mock-one-login:8080
REDIRECT_URL: http://localhost:9002/auth/redirect
REDIRECT_URL: http://localhost:9002/home/login
Original file line number Diff line number Diff line change
Expand Up @@ -31,15 +31,22 @@ public function handle(ServerRequestInterface $request): ResponseInterface
{
$requestData = $request->getQueryParams();

if (empty($requestData['redirect_url'])) {
throw new BadRequestException('Redirect URL must be provided');
}

if (empty($requestData['ui_locale'])) {
throw new BadRequestException('Ui locale must be provided');
}

$ui_locale = strtolower($requestData['ui_locale']);
$redirect_url = $requestData['redirect_url'];
$ui_locale = strtolower($requestData['ui_locale']);
if ($ui_locale !== 'en' and $ui_locale !== 'cy') {
throw new BadRequestException('ui_locale is not set to en or cy');
}

return new JsonResponse($this->authenticationRequestService->createAuthenticationRequest($ui_locale));
$authRequest = $this->authenticationRequestService->createAuthenticationRequest($ui_locale, $redirect_url);

return new JsonResponse($authRequest);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ public function __construct(
) {
}

public function createAuthenticationRequest(string $uiLocale): array
public function createAuthenticationRequest(string $uiLocale, string $redirectURL): array
{

$cachedBuilder = new MetadataProviderBuilder();
Expand Down Expand Up @@ -59,7 +59,7 @@ public function createAuthenticationRequest(string $uiLocale): array
[
'scope' => 'openid email',
'state' => $state,
'redirect_uri' => 'http://localhost:9002/auth/redirect', //TODO: use dynamic domain UML-3121
'redirect_uri' => $redirectURL,
'nonce' => $nonce,
'vtr' => '["Cl.Cm.P2"]',
'ui_locales' => $uiLocale,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,15 +53,13 @@ public function create_authentication_request(): void
$this->issuerBuilder->reveal(),
$this->cacheFactory->reveal(),
);
$authorisationRequest = $authorisationRequestService->createAuthenticationRequest('en');
$fakeRedirect = 'http://fakehost/auth/redirect';
$authorisationRequest = $authorisationRequestService->createAuthenticationRequest('en', $fakeRedirect);
$authorisationRequestUrl = $authorisationRequest['url'];
$this->assertStringContainsString('client_id=client-id', $authorisationRequestUrl);
$this->assertStringContainsString('scope=openid+email', $authorisationRequestUrl);
$this->assertStringContainsString('vtr=["Cl.Cm.P2"]', urldecode($authorisationRequestUrl));
$this->assertStringContainsString('ui_locales=en', $authorisationRequestUrl);
$this->assertStringContainsString(
'redirect_uri=http://localhost:9002/auth/redirect',
urldecode($authorisationRequestUrl)
);
$this->assertStringContainsString('redirect_uri=' . $fakeRedirect, urldecode($authorisationRequestUrl));
}
}
1 change: 1 addition & 0 deletions service-front/app/config/routes.php
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@
$app->get('/session-expired', Actor\Handler\ActorSessionExpiredHandler::class, 'session-expired');
$app->get('/session-check', Actor\Handler\ActorSessionCheckHandler::class, 'session-check');
$app->get('/session-refresh', Common\Handler\SessionRefreshHandler::class, 'session-refresh');
$app->get('/home/login', Actor\Handler\LoginPageHandler::class, 'auth-redirect');

$app->get(
'/logout',
Expand Down
28 changes: 21 additions & 7 deletions service-front/app/features/context/UI/AccountContext.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
* @property string userEmailResetToken
* @property string email
* @property string password
* @property string language
*/
class AccountContext implements Context
{
Expand All @@ -44,6 +45,7 @@ class AccountContext implements Context
private const USER_SERVICE_CAN_PASSWORD_RESET = 'UserService::canPasswordReset';
private const USER_SERVICE_COMPLETE_PASSWORD_RESET = 'UserService::completePasswordReset';
private const USER_SERVICE_DELETE_ACCOUNT = 'UserService::deleteAccount';
private const ONE_LOGIN_SERVICE_AUTHENTICATE = 'OneLoginService::authenticate';

/**
* @Then /^An account is created using (.*) (.*) (.*)$/
Expand Down Expand Up @@ -2037,6 +2039,7 @@ public function iReceiveAnEmailAndShownUniqueInstructionsOnHowToResetMyPassword(
*/
public function iAmOnTheTemporaryOneLoginPage(): void
{
$this->language = 'en';
$this->ui->visit('/home');
$this->ui->assertPageAddress('/home');
$this->ui->assertElementContainsText('button[name=sign-in-one-login]', 'Sign in via One Login');
Expand All @@ -2057,26 +2060,37 @@ public function iClickTheOneLoginButton(): void
'url' => 'http://fake.url/authorize',
]
),
self::USER_SERVICE_REQUEST_PASSWORD_RESET
self::ONE_LOGIN_SERVICE_AUTHENTICATE
)
);

$this->iDoNotFollowRedirects();
$this->ui->pressButton('Sign in via One Login');
$this->iDoFollowRedirects();

$request = $this->apiFixtures->getLastRequest();
$params = $request->getUri()->getQuery();
Assert::assertStringContainsString('ui_locale=en', $params);
}

/**
* @Then /^I am redirected to the redirect page$/
* @Then /^I am redirected to the redirect page in (English|Welsh)$/
*/
public function iAmRedirectedToTheRedirectPage(): void
public function iAmRedirectedToTheRedirectPage($language): void
{
$locationHeader = $this->ui->getSession()->getResponseHeader('Location');
$request = $this->apiFixtures->getLastRequest();
$params = $request->getUri()->getQuery();
$language = $language === 'English' ? 'en' : 'cy';

assert::assertTrue(isset($locationHeader));
assert::assertEquals($locationHeader, 'http://fake.url/authorize');
assert::assertEquals($language, $this->language);
assert::assertStringContainsString('ui_locale=' . $this->language, $params);
}

/**
* @When /^I select the Welsh language$/
*/
public function iSelectTheWelshLanguage(): void
{
$this->language = 'cy';
$this->ui->clickLink('Cymraeg');
}
}
9 changes: 8 additions & 1 deletion service-front/app/features/one-login.feature
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,11 @@
Scenario: I initiate authentication via one login
Given I am on the temporary one login page
When I click the one login button
Then I am redirected to the redirect page
Then I am redirected to the redirect page in English

@ui @actor @ff:allow_gov_one_login:true @welsh
Scenario: I initiate authentication via one login in Welsh
Given I am on the temporary one login page
And I select the Welsh language
When I click the one login button
Then I am redirected to the redirect page in Welsh
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
use Facile\OpenIDClient\Session\AuthSession;
use Laminas\Diactoros\Response\HtmlResponse;
use Laminas\Diactoros\Response\RedirectResponse;
use Mezzio\Helper\ServerUrlHelper;
use Mezzio\Helper\UrlHelper;
use Mezzio\Session\SessionMiddleware;
use Mezzio\Template\TemplateRendererInterface;
Expand All @@ -39,6 +40,7 @@ public function __construct(
UrlHelper $urlHelper,
LoggerInterface $logger,
private OneLoginService $authenticateOneLoginService,
private ServerUrlHelper $serverUrlHelper,
) {
parent::__construct($renderer, $urlHelper, $logger);
}
Expand All @@ -48,12 +50,20 @@ public function handle(ServerRequestInterface $request): ResponseInterface
$form = new OneLoginForm($this->getCsrfGuard($request));

if ($request->getMethod() === 'POST') {
$url = $this->urlHelper->generate();
$uiLocale = (str_contains($url, '/cy/') ? 'cy' : 'en');
$result = $this->authenticateOneLoginService->authenticate($uiLocale);
$signInLink = $this->serverUrlHelper->generate($this->urlHelper->generate('auth-redirect'));
$uiLocale = \Locale::getPrimaryLanguage($request->getAttribute('locale'));

if ($uiLocale === 'cy') {
$signInLink = str_replace('/cy', '', $signInLink);
}

$result = $this->authenticateOneLoginService->authenticate($uiLocale, $signInLink);
$result['customs'] = ['ui_locale' => $uiLocale];

$this
->getSession($request, SessionMiddleware::SESSION_ATTRIBUTE)
?->set(self::OIDC_AUTH_INTERFACE, AuthSession::fromArray($result));

return new RedirectResponse($result['url']);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,11 @@ public function __construct(private ApiClient $apiClient)
{
}

public function authenticate(string $uiLocale): ?array
public function authenticate(string $uiLocale, string $redirectUrl): ?array
{
return $this->apiClient->httpGet('/v1/auth-one-login', [
'ui_locale' => $uiLocale,
'ui_locale' => $uiLocale,
'redirect_url' => $redirectUrl,
]);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,13 @@ public function can_get_authentication_request_uri(): void
{
$state = 'STATE';
$nonce = 'aEwkamaos5B';
$redirect = 'FAKE_REDIRECT';
$uri = '/authorize?response_type=code
&scope=YOUR_SCOPES
&client_id=YOUR_CLIENT_ID
&state=' . $state .
'&redirect_uri=YOUR_REDIRECT_URI
&nonce=' . $nonce .
'&redirect_uri=' . $redirect .
'&nonce=' . $nonce .
'&vtr=["Cl.Cm"]
&ui_locales=en';

Expand All @@ -34,11 +35,12 @@ public function can_get_authentication_request_uri(): void
'/v1/auth-one-login',
[
'ui_locale' => 'en',
'redirect_url' => $redirect,
]
)->willReturn(['state' => $state, 'nonce' => $nonce, 'url' => $uri]);

$oneLoginService = new OneLoginService($apiClientProphecy->reveal());
$response = $oneLoginService->authenticate('en');
$response = $oneLoginService->authenticate('en', $redirect);
$this->assertEquals(['state' => $state, 'nonce' => $nonce, 'url' => $uri], $response);
}
}
Loading