Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code | Sign in
(1967)

Delta Between Two Patch Sets: Src/GoogleApis.Auth/OAuth2/Credential.cs

Issue 13972043: Issue 351: Reimplement OAuth2 (Step 3 - Tests, Flows and Credential) (Closed) Base URL: https://google-api-dotnet-client.googlecode.com/hg/
Left Patch Set: Jon Skeet review Created 10 years, 10 months ago
Right Patch Set: minor Created 10 years, 9 months ago
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments. Please Sign in to add in-line comments.
Jump to:
Left: Side by side diff | Download
Right: Side by side diff | Download
« no previous file with change/comment | « Src/GoogleApis.Auth/OAuth2/BearerToken.cs ('k') | Src/GoogleApis.Auth/OAuth2/GoogleAuthorizationCodeFlow.cs » ('j') | no next file with change/comment »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
LEFTRIGHT
1 /* 1 /*
2 Copyright 2013 Google Inc 2 Copyright 2013 Google Inc
3 3
4 Licensed under the Apache License, Version 2.0 (the "License"); 4 Licensed under the Apache License, Version 2.0 (the "License");
5 you may not use this file except in compliance with the License. 5 you may not use this file except in compliance with the License.
6 You may obtain a copy of the License at 6 You may obtain a copy of the License at
7 7
8 http://www.apache.org/licenses/LICENSE-2.0 8 http://www.apache.org/licenses/LICENSE-2.0
9 9
10 Unless required by applicable law or agreed to in writing, software 10 Unless required by applicable law or agreed to in writing, software
(...skipping 17 matching lines...) Expand all
28 { 28 {
29 /// <summary> 29 /// <summary>
30 /// OAuth 2.0 credential for accessing protected resources using an access t oken, as well as optionally refreshing· 30 /// OAuth 2.0 credential for accessing protected resources using an access t oken, as well as optionally refreshing·
31 /// the access token when it expires using a refresh token. 31 /// the access token when it expires using a refresh token.
32 /// </summary> 32 /// </summary>
33 public class Credential : IHttpExecuteInterceptor, IHttpUnsuccessfulResponse Handler, 33 public class Credential : IHttpExecuteInterceptor, IHttpUnsuccessfulResponse Handler,
34 IConfigurableHttpClientInitializer 34 IConfigurableHttpClientInitializer
35 { 35 {
36 private static readonly ILogger Logger = ApplicationContext.Logger.ForTy pe<Credential>(); 36 private static readonly ILogger Logger = ApplicationContext.Logger.ForTy pe<Credential>();
37 37
38 private readonly TokenResponse token; 38 private TokenResponse token;
39 private object lockObject = new object();
40
41 public TokenResponse Token
42 {
43 get
44 {
45 lock (lockObject)
46 {
47 return token;
48 }
49 }
50 private set
51 {
52 lock (lockObject)
53 {
54 token = value;
55 }
56 }
57 }
58
39 private readonly IAuthorizationCodeFlow flow; 59 private readonly IAuthorizationCodeFlow flow;
40 private readonly string userId; 60 private readonly string userId;
41 61
42 /// <summary>Constructs a new credential instance.</summary> 62 /// <summary>Constructs a new credential instance.</summary>
43 /// <param name="flow">Authorization code flow</param> 63 /// <param name="flow">Authorization code flow</param>
44 /// <param name="userId">User identifier</param> 64 /// <param name="userId">User identifier</param>
45 /// <param name="token">An initial token for the user</param> 65 /// <param name="token">An initial token for the user</param>
46 public Credential(IAuthorizationCodeFlow flow, string userId, TokenRespo nse token) 66 public Credential(IAuthorizationCodeFlow flow, string userId, TokenRespo nse token)
47 { 67 {
48 this.flow = flow; 68 this.flow = flow;
69 this.userId = userId;
49 this.token = token; 70 this.token = token;
50 this.userId = userId;
51 } 71 }
52 72
53 /// <summary> 73 /// <summary>
54 /// Default implementation is to try to refresh the access token if ther e is no access token or if we are 1· 74 /// Default implementation is to try to refresh the access token if ther e is no access token or if we are 1·
55 /// minute away from expiration. If token server is unavailable, it will try to use the access token even if· 75 /// minute away from expiration. If token server is unavailable, it will try to use the access token even if·
56 /// has expired. If successful, it will call <seealso cref="IAccessMetho d.Intercept"/>. 76 /// has expired. If successful, it will call <seealso cref="IAccessMetho d.Intercept"/>.
57 /// </summary> 77 /// </summary>
58 public async Task InterceptAsync(HttpRequestMessage request, Cancellatio nToken taskCancellationToken) 78 public async Task InterceptAsync(HttpRequestMessage request, Cancellatio nToken taskCancellationToken)
59 { 79 {
60 if (token.IsExpired(flow.Clock)) 80 if (Token.IsExpired(flow.Clock))
61 { 81 {
62 if (!await RefreshTokenAsync(taskCancellationToken).ConfigureAwa it(false)) 82 if (!await RefreshTokenAsync(taskCancellationToken).ConfigureAwa it(false))
63 { 83 {
64 throw new InvalidOperationException("The access token is exp ired but we can't refresh it"); 84 throw new InvalidOperationException("The access token is exp ired but we can't refresh it");
65 } 85 }
66 } 86 }
67 87
68 flow.AccessMethod.Intercept(request, token.AccessToken); 88 flow.AccessMethod.Intercept(request, Token.AccessToken);
69 } 89 }
70 90
71 /// <summary> 91 /// <summary>
72 /// Refreshes the token by calling to <seealso cref="IAuthorizationCodeF low.RefreshTokenAsync"/>. Then it· 92 /// Refreshes the token by calling to <seealso cref="IAuthorizationCodeF low.RefreshTokenAsync"/>. Then it·
73 /// updates the <see cref="TokenResponse"/> with the new token instance. 93 /// updates the <see cref="TokenResponse"/> with the new token instance.
74 /// </summary> 94 /// </summary>
75 /// <param name="taskCancellationToken">Cancellation token to cancel an operation</param> 95 /// <param name="taskCancellationToken">Cancellation token to cancel an operation</param>
76 /// <returns><c>true</c> if the token was refreshed</returns> 96 /// <returns><c>true</c> if the token was refreshed</returns>
77 private async Task<bool> RefreshTokenAsync(CancellationToken taskCancell ationToken) 97 private async Task<bool> RefreshTokenAsync(CancellationToken taskCancell ationToken)
78 { 98 {
79 if (token.RefreshToken == null) 99 if (Token.RefreshToken == null)
80 { 100 {
81 Logger.Warning("Refresh token is null, can't refresh the token!" ); 101 Logger.Warning("Refresh token is null, can't refresh the token!" );
82 return false; 102 return false;
83 } 103 }
84 104
85 // It's possible that two concurrent calls will be made to refresh t he token, in that case the last one· 105 // It's possible that two concurrent calls will be made to refresh t he token, in that case the last one·
86 // will win. 106 // will win.
87 var newToken = await flow.RefreshTokenAsync(userId, token.RefreshTok en, taskCancellationToken) 107 var newToken = await flow.RefreshTokenAsync(userId, Token.RefreshTok en, taskCancellationToken)
88 .ConfigureAwait(false); 108 .ConfigureAwait(false);
89 109
90 Logger.Info("Access token was refreshed"); 110 Logger.Info("Access token was refreshed");
91 111
92 token.CopyFrom(newToken); 112 if (newToken.RefreshToken == null)
113 {
114 newToken.RefreshToken = Token.RefreshToken;
115 }
93 116
117 Token = newToken;
94 return true; 118 return true;
95 } 119 }
96 120
97 public async Task<bool> HandleResponseAsync(HandleUnsuccessfulResponseAr gs args) 121 public async Task<bool> HandleResponseAsync(HandleUnsuccessfulResponseAr gs args)
98 { 122 {
99 // TODO(peleyal): check WWW-Authenticate header 123 // TODO(peleyal): check WWW-Authenticate header
100 if (args.Response.StatusCode == HttpStatusCode.Unauthorized) 124 if (args.Response.StatusCode == HttpStatusCode.Unauthorized)
101 { 125 {
102 return !Object.Equals(token.AccessToken, flow.AccessMethod.GetAc cessToken(args.Request)) 126 return !Object.Equals(Token.AccessToken, flow.AccessMethod.GetAc cessToken(args.Request))
103 || await RefreshTokenAsync(args.CancellationToken).Configure Await(false); 127 || await RefreshTokenAsync(args.CancellationToken).Configure Await(false);
104 } 128 }
105 129
106 return false; 130 return false;
107 } 131 }
108 132
109 public void Initialize(ConfigurableHttpClient httpClient) 133 public void Initialize(ConfigurableHttpClient httpClient)
110 { 134 {
111 httpClient.MessageHandler.ExecuteInterceptors.Add(this); 135 httpClient.MessageHandler.ExecuteInterceptors.Add(this);
112 httpClient.MessageHandler.UnsuccessfulResponseHandlers.Add(this); 136 httpClient.MessageHandler.UnsuccessfulResponseHandlers.Add(this);
113 } 137 }
114 } 138 }
115 } 139 }
LEFTRIGHT

Powered by Google App Engine
RSS Feeds Recent Issues | This issue
This is Rietveld f62528b