2021-01-19 23:07:59 +01:00
|
|
|
using System;
|
|
|
|
|
using System.Net.Http.Headers;
|
|
|
|
|
using System.Threading;
|
|
|
|
|
using System.Threading.Tasks;
|
2021-05-24 09:33:39 -07:00
|
|
|
using System.IdentityModel.Tokens.Jwt;
|
2021-01-19 23:07:59 +01:00
|
|
|
using Microsoft.Rest;
|
|
|
|
|
using IdentityModel.OidcClient;
|
|
|
|
|
using k8s.Exceptions;
|
|
|
|
|
|
|
|
|
|
namespace k8s.Authentication
|
|
|
|
|
{
|
|
|
|
|
public class OidcTokenProvider : ITokenProvider
|
|
|
|
|
{
|
|
|
|
|
private OidcClient _oidcClient;
|
|
|
|
|
private string _idToken;
|
|
|
|
|
private string _refreshToken;
|
|
|
|
|
private DateTime _expiry;
|
|
|
|
|
|
|
|
|
|
public OidcTokenProvider(string clientId, string clientSecret, string idpIssuerUrl, string idToken, string refreshToken)
|
|
|
|
|
{
|
|
|
|
|
_idToken = idToken;
|
|
|
|
|
_refreshToken = refreshToken;
|
|
|
|
|
_oidcClient = getClient(clientId, clientSecret, idpIssuerUrl);
|
2021-05-24 09:33:39 -07:00
|
|
|
_expiry = getExpiryFromToken();
|
2021-01-19 23:07:59 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public async Task<AuthenticationHeaderValue> GetAuthenticationHeaderAsync(CancellationToken cancellationToken)
|
|
|
|
|
{
|
2021-05-24 09:33:39 -07:00
|
|
|
if (_idToken == null || DateTime.UtcNow.AddSeconds(30) > _expiry)
|
2021-01-19 23:07:59 +01:00
|
|
|
{
|
|
|
|
|
await RefreshToken().ConfigureAwait(false);
|
|
|
|
|
}
|
|
|
|
|
|
2021-05-24 09:33:39 -07:00
|
|
|
return new AuthenticationHeaderValue("Bearer", _idToken);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private DateTime getExpiryFromToken()
|
|
|
|
|
{
|
|
|
|
|
int expiry;
|
|
|
|
|
var handler = new JwtSecurityTokenHandler();
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
var token = handler.ReadJwtToken(_idToken);
|
|
|
|
|
expiry = token.Payload.Exp ?? 0;
|
|
|
|
|
}
|
|
|
|
|
catch
|
|
|
|
|
{
|
|
|
|
|
expiry = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return DateTimeOffset.FromUnixTimeSeconds(expiry).UtcDateTime;
|
2021-01-19 23:07:59 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private OidcClient getClient(string clientId, string clientSecret, string idpIssuerUrl)
|
|
|
|
|
{
|
|
|
|
|
OidcClientOptions options = new OidcClientOptions
|
|
|
|
|
{
|
|
|
|
|
ClientId = clientId,
|
|
|
|
|
ClientSecret = clientSecret ?? "",
|
|
|
|
|
Authority = idpIssuerUrl,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
return new OidcClient(options);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private async Task RefreshToken()
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
2021-05-24 09:33:39 -07:00
|
|
|
var result = await _oidcClient.RefreshTokenAsync(_refreshToken).ConfigureAwait(false);
|
|
|
|
|
|
|
|
|
|
if (result.IsError)
|
|
|
|
|
{
|
|
|
|
|
throw new Exception(result.Error);
|
|
|
|
|
}
|
|
|
|
|
|
2021-01-19 23:07:59 +01:00
|
|
|
_idToken = result.IdentityToken;
|
|
|
|
|
_refreshToken = result.RefreshToken;
|
|
|
|
|
_expiry = result.AccessTokenExpiration;
|
|
|
|
|
}
|
|
|
|
|
catch (Exception e)
|
|
|
|
|
{
|
|
|
|
|
throw new KubernetesClientException($"Unable to refresh OIDC token. \n {e.Message}", e);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|