argo-cd

Форк
0
151 строка · 4.9 Кб
1
import {
2
    AuthorizationServer,
3
    Client,
4
    authorizationCodeGrantRequest,
5
    calculatePKCECodeChallenge,
6
    discoveryRequest,
7
    expectNoState,
8
    generateRandomCodeVerifier,
9
    isOAuth2Error,
10
    parseWwwAuthenticateChallenges,
11
    processAuthorizationCodeOpenIDResponse,
12
    processDiscoveryResponse,
13
    validateAuthResponse
14
} from 'oauth4webapi';
15
import {AuthSettings} from '../../shared/models';
16

17
export const discoverAuthServer = (issuerURL: URL): Promise<AuthorizationServer> => discoveryRequest(issuerURL).then(res => processDiscoveryResponse(issuerURL, res));
18

19
export const PKCECodeVerifier = {
20
    get: () => sessionStorage.getItem(window.btoa('code_verifier')),
21
    set: (codeVerifier: string) => sessionStorage.setItem(window.btoa('code_verifier'), codeVerifier),
22
    unset: () => sessionStorage.removeItem(window.btoa('code_verifier'))
23
};
24

25
export const getPKCERedirectURI = () => {
26
    const currentOrigin = new URL(window.location.origin);
27

28
    currentOrigin.pathname = '/pkce/verify';
29

30
    return currentOrigin;
31
};
32

33
export class PKCELoginError extends Error {
34
    constructor(message: string) {
35
        super(message);
36
        this.name = 'PKCELoginError';
37
    }
38
}
39

40
const validateAndGetOIDCForPKCE = async (oidcConfig: AuthSettings['oidcConfig']) => {
41
    if (!oidcConfig) {
42
        throw new PKCELoginError('No OIDC Config found');
43
    }
44

45
    let issuerURL: URL;
46
    try {
47
        issuerURL = new URL(oidcConfig.issuer);
48
    } catch (e) {
49
        throw new PKCELoginError(`Invalid oidc issuer ${oidcConfig.issuer}`);
50
    }
51

52
    if (!oidcConfig.clientID) {
53
        throw new PKCELoginError('No OIDC Client Id found');
54
    }
55

56
    let authorizationServer: AuthorizationServer;
57
    try {
58
        authorizationServer = await discoverAuthServer(issuerURL);
59
    } catch (e) {
60
        throw new PKCELoginError(e);
61
    }
62

63
    return {
64
        issuerURL,
65
        authorizationServer,
66
        clientID: oidcConfig.clientID
67
    };
68
};
69

70
export const pkceLogin = async (oidcConfig: AuthSettings['oidcConfig'], redirectURI: string) => {
71
    const {authorizationServer} = await validateAndGetOIDCForPKCE(oidcConfig);
72

73
    if (!authorizationServer.authorization_endpoint) {
74
        throw new PKCELoginError('No Authorization Server endpoint found');
75
    }
76

77
    const codeVerifier = generateRandomCodeVerifier();
78

79
    const codeChallange = await calculatePKCECodeChallenge(codeVerifier);
80

81
    const authorizationServerConsentScreen = new URL(authorizationServer.authorization_endpoint);
82

83
    authorizationServerConsentScreen.searchParams.set('client_id', oidcConfig.clientID);
84
    authorizationServerConsentScreen.searchParams.set('code_challenge', codeChallange);
85
    authorizationServerConsentScreen.searchParams.set('code_challenge_method', 'S256');
86
    authorizationServerConsentScreen.searchParams.set('redirect_uri', redirectURI);
87
    authorizationServerConsentScreen.searchParams.set('response_type', 'code');
88
    authorizationServerConsentScreen.searchParams.set('scope', oidcConfig.scopes.join(' '));
89

90
    PKCECodeVerifier.set(codeVerifier);
91

92
    window.location.replace(authorizationServerConsentScreen.toString());
93
};
94

95
export const pkceCallback = async (queryParams: string, oidcConfig: AuthSettings['oidcConfig'], redirectURI: string) => {
96
    const codeVerifier = PKCECodeVerifier.get();
97

98
    if (!codeVerifier) {
99
        throw new PKCELoginError('No code verifier found in session');
100
    }
101

102
    let callbackQueryParams = new URLSearchParams();
103
    try {
104
        callbackQueryParams = new URLSearchParams(queryParams);
105
    } catch (e) {
106
        throw new PKCELoginError('Invalid query parameters');
107
    }
108

109
    if (!callbackQueryParams.get('code')) {
110
        throw new PKCELoginError('No code in query parameters');
111
    }
112

113
    if (callbackQueryParams.get('state') === '') {
114
        callbackQueryParams.delete('state');
115
    }
116

117
    const {authorizationServer} = await validateAndGetOIDCForPKCE(oidcConfig);
118

119
    const client: Client = {
120
        client_id: oidcConfig.clientID,
121
        token_endpoint_auth_method: 'none'
122
    };
123

124
    const params = validateAuthResponse(authorizationServer, client, callbackQueryParams, expectNoState);
125

126
    if (isOAuth2Error(params)) {
127
        throw new PKCELoginError('Error validating auth response');
128
    }
129

130
    const response = await authorizationCodeGrantRequest(authorizationServer, client, params, redirectURI, codeVerifier);
131

132
    const authChallengeExtract = parseWwwAuthenticateChallenges(response);
133

134
    if (authChallengeExtract?.length > 0) {
135
        throw new PKCELoginError('Error parsing authentication challenge');
136
    }
137

138
    const result = await processAuthorizationCodeOpenIDResponse(authorizationServer, client, response);
139

140
    if (isOAuth2Error(result)) {
141
        throw new PKCELoginError(`Error getting token ${result.error_description}`);
142
    }
143

144
    if (!result.id_token) {
145
        throw new PKCELoginError('No token in response');
146
    }
147

148
    document.cookie = `argocd.token=${result.id_token}; path=/`;
149

150
    window.location.replace('/applications');
151
};
152

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.