146 lines
6.3 KiB
C#
146 lines
6.3 KiB
C#
/*
|
|
Copyright 2013 Google Inc
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
you may not use this file except in compliance with the License.
|
|
You may obtain a copy of the License at
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
See the License for the specific language governing permissions and
|
|
limitations under the License.
|
|
*/
|
|
|
|
using System;
|
|
|
|
using Google.Apis.Util;
|
|
using System.Threading.Tasks;
|
|
using System.Net.Http;
|
|
using Google.Apis.Json;
|
|
using Google.Apis.Logging;
|
|
|
|
namespace Google.Apis.Auth.OAuth2.Responses
|
|
{
|
|
/// <summary>
|
|
/// OAuth 2.0 model for a successful access token response as specified in
|
|
/// http://tools.ietf.org/html/rfc6749#section-5.1.
|
|
/// </summary>
|
|
public class TokenResponse
|
|
{
|
|
private const int TokenExpiryTimeWindowSeconds = 60 * 5; // Refresh token 5 minutes before it expires.
|
|
|
|
/// <summary>Gets or sets the access token issued by the authorization server.</summary>
|
|
[Newtonsoft.Json.JsonPropertyAttribute("access_token")]
|
|
public string AccessToken { get; set; }
|
|
|
|
/// <summary>
|
|
/// Gets or sets the token type as specified in http://tools.ietf.org/html/rfc6749#section-7.1.
|
|
/// </summary>
|
|
[Newtonsoft.Json.JsonPropertyAttribute("token_type")]
|
|
public string TokenType { get; set; }
|
|
|
|
/// <summary>Gets or sets the lifetime in seconds of the access token.</summary>
|
|
[Newtonsoft.Json.JsonPropertyAttribute("expires_in")]
|
|
public Nullable<long> ExpiresInSeconds { get; set; }
|
|
|
|
/// <summary>
|
|
/// Gets or sets the refresh token which can be used to obtain a new access token.
|
|
/// For example, the value "3600" denotes that the access token will expire in one hour from the time the
|
|
/// response was generated.
|
|
/// </summary>
|
|
[Newtonsoft.Json.JsonPropertyAttribute("refresh_token")]
|
|
public string RefreshToken { get; set; }
|
|
|
|
/// <summary>
|
|
/// Gets or sets the scope of the access token as specified in http://tools.ietf.org/html/rfc6749#section-3.3.
|
|
/// </summary>
|
|
[Newtonsoft.Json.JsonPropertyAttribute("scope")]
|
|
public string Scope { get; set; }
|
|
|
|
/// <summary>
|
|
/// Gets or sets the id_token, which is a JSON Web Token (JWT) as specified in http://tools.ietf.org/html/draft-ietf-oauth-json-web-token
|
|
/// </summary>
|
|
[Newtonsoft.Json.JsonPropertyAttribute("id_token")]
|
|
public string IdToken { get; set; }
|
|
|
|
/// <summary>
|
|
/// The date and time that this token was issued, expressed in the system time zone.
|
|
/// This property only exists for backward compatibility; it can cause inappropriate behavior around
|
|
/// time zone transitions (e.g. daylight saving transitions).
|
|
/// </summary>
|
|
[Obsolete("Use IssuedUtc instead")]
|
|
[Newtonsoft.Json.JsonPropertyAttribute(Order = 1)] // Serialize this before IssuedUtc, so that IssuedUtc takes priority when deserializing
|
|
public DateTime Issued
|
|
{
|
|
get { return IssuedUtc.ToLocalTime(); }
|
|
set { IssuedUtc = value.ToUniversalTime(); }
|
|
}
|
|
|
|
/// <summary>
|
|
/// The date and time that this token was issued, expressed in UTC.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// This should be set by the CLIENT after the token was received from the server.
|
|
/// </remarks>
|
|
[Newtonsoft.Json.JsonPropertyAttribute(Order = 2)]
|
|
public DateTime IssuedUtc { get; set; }
|
|
|
|
/// <summary>
|
|
/// Returns <c>true</c> if the token is expired or it's going to be expired in the next minute.
|
|
/// </summary>
|
|
public bool IsExpired(IClock clock)
|
|
{
|
|
if (AccessToken == null || !ExpiresInSeconds.HasValue)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
return IssuedUtc.AddSeconds(ExpiresInSeconds.Value - TokenExpiryTimeWindowSeconds) <= clock.UtcNow;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Asynchronously parses a <see cref="TokenResponse"/> instance from the specified <see cref="HttpResponseMessage"/>.
|
|
/// </summary>
|
|
/// <param name="response">The http response from which to parse the token.</param>
|
|
/// <param name="clock">The clock used to set the <see cref="Issued"/> value of the token.</param>
|
|
/// <param name="logger">The logger used to output messages incase of error.</param>
|
|
/// <exception cref="TokenResponseException">
|
|
/// The response was not successful or there is an error parsing the response into valid <see cref="TokenResponse"/> instance.
|
|
/// </exception>
|
|
/// <returns>
|
|
/// A task containing the <see cref="TokenResponse"/> parsed form the response message.
|
|
/// </returns>
|
|
public static async Task<TokenResponse> FromHttpResponseAsync(HttpResponseMessage response, Util.IClock clock, ILogger logger)
|
|
{
|
|
var content = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
|
|
var typeName = "";
|
|
try
|
|
{
|
|
if (!response.IsSuccessStatusCode)
|
|
{
|
|
typeName = nameof(TokenErrorResponse);
|
|
var error = NewtonsoftJsonSerializer.Instance.Deserialize<TokenErrorResponse>(content);
|
|
throw new TokenResponseException(error, response.StatusCode);
|
|
}
|
|
|
|
// Gets the token and sets its issued time.
|
|
typeName = nameof(TokenResponse);
|
|
var newToken = NewtonsoftJsonSerializer.Instance.Deserialize<TokenResponse>(content);
|
|
newToken.IssuedUtc = clock.UtcNow;
|
|
return newToken;
|
|
}
|
|
catch (Newtonsoft.Json.JsonException ex)
|
|
{
|
|
logger.Error(ex, $"Exception was caught when deserializing {typeName}. Content is: {content}");
|
|
throw new TokenResponseException(new TokenErrorResponse
|
|
{
|
|
Error = "Server response does not contain a JSON object. Status code is: " + response.StatusCode
|
|
}, response.StatusCode);
|
|
}
|
|
}
|
|
}
|
|
}
|