Skip to content

Commit

Permalink
Merge pull request #1737 from SUNET/eunju-security-zone
Browse files Browse the repository at this point in the history
Eunju security zone
  • Loading branch information
alessandrodi authored Jun 24, 2024
2 parents c299461 + b6c2c13 commit f6a7de1
Show file tree
Hide file tree
Showing 22 changed files with 478 additions and 231 deletions.
69 changes: 69 additions & 0 deletions src/apis/eduidAuthn.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
/*
* Code and data structures for talking to the Authn backend microservice.
*/

import { createAsyncThunk, PayloadAction } from "@reduxjs/toolkit";
import { EduIDAppDispatch, EduIDAppRootState } from "eduid-init-app";
import { KeyValues, makeGenericRequest, RequestThunkAPI } from "./common";
import { GetStatusRequest, GetStatusResponse } from "./eduidEidas";

type DispatchWithAuthn = EduIDAppDispatch;
type StateWithAuthn = EduIDAppRootState;

export interface AuthenticateResponse {
location: string;
}

export interface AuthenticateRequest {
frontend_action?: string;
}

/*********************************************************************************************************************/
/**
* @public
* @function authenticate
* @desc
*/
export const authenticate = createAsyncThunk<
AuthenticateResponse, // return type
AuthenticateRequest, // args type
{ dispatch: DispatchWithAuthn; state: StateWithAuthn }
>("authn/authenticate", async (args, thunkAPI) => {
const body: KeyValues = args;
return makeAuthnRequest<AuthenticateResponse>(thunkAPI, "authenticate", body) // return type
.then((response) => response.payload)
.catch((err) => thunkAPI.rejectWithValue(err));
});

/*********************************************************************************************************************/
/**
* @public
* @function authnGetStatus
* @desc Redux async thunk to fetch status for an earlier operation.
*/
export const authnGetStatus = createAsyncThunk<
GetStatusResponse, // return type
GetStatusRequest, // args type
{ dispatch: DispatchWithAuthn; state: StateWithAuthn }
>("authn/getStatus", async (args, thunkAPI) => {
const body: KeyValues = args;
return makeAuthnRequest<GetStatusResponse>(thunkAPI, "get-status", body)
.then((response) => response.payload)
.catch((err) => thunkAPI.rejectWithValue(err));
});

/*********************************************************************************************************************/
async function makeAuthnRequest<T>(
thunkAPI: RequestThunkAPI,
endpoint: string,
body?: KeyValues,
data?: KeyValues
): Promise<PayloadAction<T, string, never, boolean>> {
const state = thunkAPI.getState();

if (!state.config.authn_service_url) {
throw new Error("Missing configuration state.config.authn_service_url");
}

return makeGenericRequest<T>(thunkAPI, state.config.authn_service_url, endpoint, body, data);
}
8 changes: 4 additions & 4 deletions src/apis/eduidBankid.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ export const bankIDVerifyIdentity = createAsyncThunk<
>("bankid/verifyIdentity", async (args, thunkAPI) => {
const body: KeyValues = args;
if (body.frontend_action === undefined) {
body.frontend_action = "bankidVerifyIdentity";
body.frontend_action = "verifyIdentity";
}

return makeBankIDRequest<VerifyIdentityResponse>(thunkAPI, "verify-identity", body)
Expand Down Expand Up @@ -68,7 +68,7 @@ export const bankIDMfaAuthenticate = createAsyncThunk<
>("bankid/mfaAuthenticate", async (args, thunkAPI) => {
const body: KeyValues = args;
if (body.frontend_action === undefined) {
body.frontend_action = "bankidMfaAuthenticate";
body.frontend_action = "loginMfaAuthn";
}
return makeBankIDRequest<MfaAuthenticateResponse>(thunkAPI, "mfa-authenticate", body)
.then((response) => response.payload)
Expand Down Expand Up @@ -96,7 +96,7 @@ export const bankIDVerifyCredential = createAsyncThunk<
>("bankid/verifyCredential", async (args, thunkAPI) => {
const body: KeyValues = args;
if (body.frontend_action === undefined) {
body.frontend_action = "bankidVerifyCredential";
body.frontend_action = "verifyCredential";
}
return makeBankIDRequest<VerifyCredentialResponse>(thunkAPI, "verify-credential", body)
.then((response) => response.payload)
Expand All @@ -116,7 +116,7 @@ export const bankIDGetStatus = createAsyncThunk<
{ dispatch: DispatchWithBankID; state: StateWithBankID }
>("bankid/getStatus", async (args, thunkAPI) => {
const body: KeyValues = args;
return makeBankIDRequest<GetStatusResponse>(thunkAPI, "get_status", body)
return makeBankIDRequest<GetStatusResponse>(thunkAPI, "get-status", body)
.then((response) => response.payload)
.catch((err) => thunkAPI.rejectWithValue(err));
});
Expand Down
8 changes: 4 additions & 4 deletions src/apis/eduidEidas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ export const eidasVerifyIdentity = createAsyncThunk<
>("eidas/verifyIdentity", async (args, thunkAPI) => {
const body: KeyValues = args;
if (body.frontend_action === undefined) {
body.frontend_action = "eidasVerifyIdentity";
body.frontend_action = "verifyIdentity";
}
return makeEidasRequest<VerifyIdentityResponse>(thunkAPI, "verify-identity", body)
.then((response) => response.payload)
Expand Down Expand Up @@ -69,7 +69,7 @@ export const eidasVerifyCredential = createAsyncThunk<
>("eidas/verifyCredential", async (args, thunkAPI) => {
const body: KeyValues = args;
if (body.frontend_action === undefined) {
body.frontend_action = "eidasVerifyCredential";
body.frontend_action = "verifyCredential";
}
return makeEidasRequest<VerifyCredentialResponse>(thunkAPI, "verify-credential", body)
.then((response) => response.payload)
Expand All @@ -96,7 +96,7 @@ export const eidasMfaAuthenticate = createAsyncThunk<
>("eidas/mfaAuthenticate", async (args, thunkAPI) => {
const body: KeyValues = args;
if (body.frontend_action === undefined) {
body.frontend_action = "eidasMfaAuthenticate";
body.frontend_action = "loginMfaAuthn";
}
return makeEidasRequest<MfaAuthenticateResponse>(thunkAPI, "mfa-authenticate", body)
.then((response) => response.payload)
Expand Down Expand Up @@ -129,7 +129,7 @@ export const eidasGetStatus = createAsyncThunk<
{ dispatch: DispatchWithEidas; state: StateWithEidas }
>("eidas/getStatus", async (args, thunkAPI) => {
const body: KeyValues = args;
return makeEidasRequest<GetStatusResponse>(thunkAPI, "get_status", body)
return makeEidasRequest<GetStatusResponse>(thunkAPI, "get-status", body)
.then((response) => response.payload)
.catch((err) => thunkAPI.rejectWithValue(err));
});
Expand Down
2 changes: 1 addition & 1 deletion src/apis/eduidSvipe.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ export const svipeGetStatus = createAsyncThunk<
{ dispatch: DispatchWithSvipe; state: StateWithSvipe }
>("svipe/getStatus", async (args, thunkAPI) => {
const body: KeyValues = args;
return makeSvipeRequest<GetStatusResponse>(thunkAPI, "get_status", body)
return makeSvipeRequest<GetStatusResponse>(thunkAPI, "get-status", body)
.then((response) => response.payload)
.catch((err) => thunkAPI.rejectWithValue(err));
});
Expand Down
26 changes: 13 additions & 13 deletions src/components/Common/ConfirmModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,19 @@ import CustomInput from "./CustomInput";
import EduIDButton from "./EduIDButton";

interface ConfirmModalProps {
id: string;
title: React.ReactNode;
placeholder: string;
showModal: boolean;
closeModal: () => void;
handleConfirm: (values: { [key: string]: string }) => void;
modalFormLabel: React.ReactNode;
validationError?: string;
validationPattern?: RegExp;
helpBlock?: React.ReactNode;
resendMarkup?: React.ReactNode;
captcha?: GetCaptchaResponse;
submitButtonText?: React.ReactNode;
readonly id: string;
readonly title: React.ReactNode;
readonly placeholder: string;
readonly showModal: boolean;
readonly closeModal: () => void;
readonly handleConfirm: (values: { [key: string]: string }) => void;
readonly modalFormLabel: React.ReactNode;
readonly validationError?: string;
readonly validationPattern?: RegExp;
readonly helpBlock?: React.ReactNode;
readonly resendMarkup?: React.ReactNode;
readonly captcha?: GetCaptchaResponse;
readonly submitButtonText?: React.ReactNode;
}

function ConfirmModal(props: ConfirmModalProps): JSX.Element {
Expand Down
1 change: 0 additions & 1 deletion src/components/Common/ConfirmUserInfo.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@ export function ConfirmUserInfo(props: ConfirmUserInfoProps) {
<input
autoComplete="new-password"
type="password"
name="display-none-new-password"
id="display-none-new-password"
defaultValue={props.new_password ? props.new_password : ""}
/>
Expand Down
57 changes: 33 additions & 24 deletions src/components/Common/ExternalReturnHandler.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { authnGetStatus } from "apis/eduidAuthn";
import { bankIDGetStatus } from "apis/eduidBankid";
import { GetStatusResponse, eidasGetStatus } from "apis/eduidEidas";
import { svipeGetStatus } from "apis/eduidSvipe";
Expand All @@ -20,31 +21,29 @@ export function ExternalReturnHandler() {

function processStatus(response: GetStatusResponse) {
const status = response;
if (status?.method) {
// Status has been fetched

if (status.status) {
dispatch(showNotification({ message: status.status, level: status.error ? "error" : "info" }));
}

if (status.frontend_action) {
// actionToRoute is a mapping from frontend_action values to where in the Dashboard application
// the user should be returned to
const actionToRoute: { [key: string]: string } = {
eidasVerifyIdentity: "/profile/verify-identity/",
eidasVerifyCredential: "/profile/settings/advanced-settings/",
svipeidVerifyIdentity: "/profile/verify-identity/",
bankidVerifyIdentity: "/profile/verify-identity/",
};
const _path = actionToRoute[status.frontend_action];
if (_path) {
navigate(_path);
return;
}
// Status has been fetched
if (status.status) {
dispatch(showNotification({ message: status.status, level: status.error ? "error" : "info" }));
}
if (status.frontend_action) {
// actionToRoute is a mapping from frontend_action values to where in the Dashboard application
// the user should be returned to
const actionToRoute: { [key: string]: string } = {
verifyIdentity: "/profile/verify-identity/",
verifyCredential: "/profile/settings/advanced-settings/",
changepwAuthn: "/profile/chpass",
terminateAccountAuthn: "/",
addSecurityKeyAuthn: "/profile/settings/advanced-settings/",
removeSecurityKeyAuthn: "/profile/settings/advanced-settings/",
};
const _path = actionToRoute[status.frontend_action];
if (_path) {
navigate(_path);
return;
}

navigate("/profile/"); // GOTO start
}

navigate("/profile/"); // GOTO start
}

async function fetchEidasStatus(authn_id: string) {
Expand All @@ -68,8 +67,15 @@ export function ExternalReturnHandler() {
}
}

async function fetchAuthStatus(authn_id: string) {
const response = await dispatch(authnGetStatus({ authn_id: authn_id }));
if (authnGetStatus.fulfilled.match(response)) {
processStatus(response.payload);
}
}

useEffect(() => {
if (params.authn_id && params.app_name === "eidas") {
if (params.authn_id && params.app_name === "eidas" && app_loaded) {
fetchEidasStatus(params.authn_id).catch(console.error);
}
if (params.authn_id && params.app_name === "svipe_id") {
Expand All @@ -78,6 +84,9 @@ export function ExternalReturnHandler() {
if (params.authn_id && params.app_name === "bankid" && app_loaded) {
fetchBankIDStatus(params.authn_id).catch(console.error);
}
if (params.authn_id && params.app_name === "authn" && app_loaded) {
fetchAuthStatus(params.authn_id).catch(console.error);
}
}, [params, app_loaded]);

return null;
Expand Down
Loading

0 comments on commit f6a7de1

Please sign in to comment.