forked from kubernetes-client/javascript
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathoidc_auth.ts
118 lines (104 loc) · 3.94 KB
/
oidc_auth.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
import https = require('https');
import { Client, ClientMetadata, Issuer } from 'openid-client';
import request = require('request');
import { base64url } from 'rfc4648';
import { TextDecoder } from 'util';
import { Authenticator } from './auth';
import { User } from './config_types';
interface JwtObj {
header: any;
payload: any;
signature: string;
}
export class OpenIDConnectAuth implements Authenticator {
public static decodeJWT(token: string): JwtObj | null {
const parts = token.split('.');
if (parts.length !== 3) {
return null;
}
const header = JSON.parse(new TextDecoder().decode(base64url.parse(parts[0], { loose: true })));
const payload = JSON.parse(new TextDecoder().decode(base64url.parse(parts[1], { loose: true })));
const signature = parts[2];
return {
header,
payload,
signature,
};
}
public static expirationFromToken(token: string): number {
const jwt = OpenIDConnectAuth.decodeJWT(token);
if (!jwt) {
return 0;
}
return jwt.payload.exp;
}
// public for testing purposes.
private currentTokenExpiration: number = 0;
public isAuthProvider(user: User): boolean {
if (!user.authProvider) {
return false;
}
return user.authProvider.name === 'oidc';
}
/**
* Setup the authentication header for oidc authed clients
* @param user user info
* @param opts request options
* @param overrideClient for testing, a preconfigured oidc client
*/
public async applyAuthentication(
user: User,
opts: request.Options | https.RequestOptions,
overrideClient?: any,
): Promise<void> {
const token = await this.getToken(user, overrideClient);
if (token) {
opts.headers!.Authorization = `Bearer ${token}`;
}
}
private async getToken(user: User, overrideClient?: Client): Promise<string | null> {
if (!user.authProvider.config) {
return null;
}
if (!user.authProvider.config['client-secret']) {
user.authProvider.config['client-secret'] = '';
}
if (!user.authProvider.config || !user.authProvider.config['id-token']) {
return null;
}
return this.refresh(user, overrideClient);
}
private async refresh(user: User, overrideClient?: Client): Promise<string | null> {
if (this.currentTokenExpiration === 0) {
this.currentTokenExpiration = OpenIDConnectAuth.expirationFromToken(
user.authProvider.config['id-token'],
);
}
if (Date.now() / 1000 > this.currentTokenExpiration) {
if (
!user.authProvider.config['client-id'] ||
!user.authProvider.config['refresh-token'] ||
!user.authProvider.config['idp-issuer-url']
) {
return null;
}
const client = overrideClient ? overrideClient : await this.getClient(user);
const newToken = await client.refresh(user.authProvider.config['refresh-token']);
user.authProvider.config['id-token'] = newToken.id_token;
user.authProvider.config['refresh-token'] = newToken.refresh_token;
this.currentTokenExpiration = newToken.expires_at || 0;
}
return user.authProvider.config['id-token'];
}
private async getClient(user: User): Promise<Client> {
const oidcIssuer = await Issuer.discover(user.authProvider.config['idp-issuer-url']);
const metadata: ClientMetadata = {
client_id: user.authProvider.config['client-id'],
client_secret: user.authProvider.config['client-secret'],
};
if (!user.authProvider.config['client-secret']) {
metadata.token_endpoint_auth_method = 'none';
}
return new oidcIssuer.Client(metadata);
}
}