@@ -40,37 +40,58 @@ export class AnonymousAuthService implements IAuthService {
40
40
}
41
41
}
42
42
43
+ interface StaticCredentialsAuthOptions {
44
+ /** Custom ssl sertificates. If you use it in driver, you must use it here too */
45
+ sslCredentials ?: ISslCredentials ;
46
+ /**
47
+ * Timeout for token request in milliseconds
48
+ * @default 10 * 1000
49
+ */
50
+ tokenRequestTimeout ?: number ;
51
+ /** Expiration time for token in milliseconds
52
+ * @default 6 * 60 * 60 * 1000
53
+ */
54
+ tokenExpirationTimeout ?: number
55
+ }
43
56
44
57
export class StaticCredentialsAuthService implements IAuthService {
45
- private tokenExpirationTimeout = 30 * 60 * 1000 ;
46
- private tokenRequestTimeout = 10 * 1000 ;
47
- private tokenTimestamp : DateTime | null ;
48
- private token : string = '' ;
49
- private tokenUpdateInProgress : Boolean = false ;
58
+ private readonly tokenRequestTimeout = 10 * 1000 ;
59
+ private readonly tokenExpirationTimeout = 6 * 60 * 60 * 1000 ;
60
+ private tokenTimestamp : DateTime | null ;
61
+ private token : string = "" ;
62
+ private tokenUpdatePromise : Promise < any > | null = null ;
50
63
private user : string ;
51
64
private password : string ;
52
- private endpoint : string
53
- private sslCredentials : ISslCredentials | undefined
65
+ private endpoint : string ;
66
+ private sslCredentials : ISslCredentials | undefined ;
54
67
55
68
private readonly GrpcService = class extends GrpcService < Ydb . Auth . V1 . AuthService > {
56
69
constructor ( endpoint : string , sslCredentials ?: ISslCredentials ) {
57
- super ( endpoint , ' Ydb.Auth.V1.AuthService' , Ydb . Auth . V1 . AuthService , sslCredentials )
70
+ super ( endpoint , " Ydb.Auth.V1.AuthService" , Ydb . Auth . V1 . AuthService , sslCredentials ) ;
58
71
}
59
72
60
73
login ( request : Ydb . Auth . ILoginRequest ) {
61
- return this . api . login ( request )
74
+ return this . api . login ( request ) ;
62
75
}
63
76
64
- destroy ( ) { this . api . end ( ) }
65
-
66
- }
77
+ destroy ( ) {
78
+ this . api . end ( ) ;
79
+ }
80
+ } ;
67
81
68
- constructor ( user : string , password : string , endpoint : string , sslCredentials ?: ISslCredentials ) {
82
+ constructor (
83
+ user : string ,
84
+ password : string ,
85
+ endpoint : string ,
86
+ options ?: StaticCredentialsAuthOptions
87
+ ) {
88
+ this . tokenTimestamp = null ;
69
89
this . user = user ;
70
90
this . password = password ;
71
91
this . endpoint = endpoint ;
72
- this . sslCredentials = sslCredentials
73
- this . tokenTimestamp = null ;
92
+ this . sslCredentials = options ?. sslCredentials ;
93
+ if ( options ?. tokenRequestTimeout ) this . tokenRequestTimeout = options . tokenRequestTimeout ;
94
+ if ( options ?. tokenExpirationTimeout ) this . tokenExpirationTimeout = options . tokenExpirationTimeout ;
74
95
}
75
96
76
97
private get expired ( ) {
@@ -80,45 +101,38 @@ export class StaticCredentialsAuthService implements IAuthService {
80
101
}
81
102
82
103
private async sendTokenRequest ( ) : Promise < AuthServiceResult > {
83
- let runtimeAuthService = new this . GrpcService ( this . endpoint , this . sslCredentials )
104
+ let runtimeAuthService = new this . GrpcService ( this . endpoint , this . sslCredentials ) ;
84
105
try {
85
106
const tokenPromise = runtimeAuthService . login ( {
86
107
user : this . user ,
87
- password : this . password
108
+ password : this . password ,
88
109
} ) ;
89
110
const response = await withTimeout < Ydb . Auth . LoginResponse > ( tokenPromise , this . tokenRequestTimeout ) ;
90
111
const result = AuthServiceResult . decode ( getOperationPayload ( response ) ) ;
91
- runtimeAuthService . destroy ( )
92
- return result
112
+ runtimeAuthService . destroy ( ) ;
113
+ return result ;
93
114
} catch ( error ) {
94
- throw new Error ( "Can't login by user and password " + String ( error ) )
115
+ throw new Error ( "Can't login by user and password " + String ( error ) ) ;
95
116
}
96
-
97
117
}
98
118
99
119
private async updateToken ( ) {
100
- this . tokenUpdateInProgress = true
101
- const { token} = await this . sendTokenRequest ( ) ;
120
+ const { token } = await this . sendTokenRequest ( ) ;
102
121
if ( token ) {
103
122
this . token = token ;
104
123
this . tokenTimestamp = DateTime . utc ( ) ;
105
- this . tokenUpdateInProgress = false
106
124
} else {
107
- this . tokenUpdateInProgress = false
108
- throw new Error ( 'Received empty token from credentials!' ) ;
125
+ throw new Error ( "Received empty token from credentials!" ) ;
109
126
}
110
127
}
111
128
112
- private async waitUntilTokenUpdated ( ) {
113
- while ( this . tokenUpdateInProgress ) { await sleep ( 1 ) }
114
- return
115
- }
116
-
117
129
public async getAuthMetadata ( ) : Promise < grpc . Metadata > {
118
- if ( this . expired ) {
119
- // block updateToken calls while token updating
120
- if ( this . tokenUpdateInProgress ) await this . waitUntilTokenUpdated ( )
121
- else await this . updateToken ( ) ;
130
+ if ( this . expired || this . tokenUpdatePromise ) {
131
+ if ( ! this . tokenUpdatePromise ) {
132
+ this . tokenUpdatePromise = this . updateToken ( ) ;
133
+ }
134
+ await this . tokenUpdatePromise ;
135
+ this . tokenUpdatePromise = null ;
122
136
}
123
137
return makeCredentialsMetadata ( this . token ) ;
124
138
}
0 commit comments