2 * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
4 * Licensed under the Apache License, Version 2.0 (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
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an AS IS BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
18 using System.Collections.Generic;
19 using System.Runtime.InteropServices;
20 using System.Threading.Tasks;
22 namespace Tizen.Account.OAuth2
25 /// An abstract class to represent various OAuth 2.0 authorization code flows.
26 /// Refer to http://tools.ietf.org/html/rfc6749 about OAuth 2.0 protocols.
27 /// Also service provider document needs to be referred for using end points and additional parameters.
29 /// <since_tizen> 3 </since_tizen>
30 public abstract class Authorizer : IDisposable
33 internal IntPtr _managerHandle;
34 private bool _disposed = false;
37 /// Constructor for Authoirzer instances
39 /// <since_tizen> 3 </since_tizen>
42 int ret = Interop.Manager.Create(out _managerHandle);
43 if (ret != (int)OAuth2Error.None)
45 Log.Error(ErrorFactory.LogTag, "Interop failed");
46 throw ErrorFactory.GetException(ret);
51 /// Destructor of the Authorizer class.
53 /// <since_tizen> 3 </since_tizen>
60 /// Indicates if the current instance is already handling an authorization request
62 /// <since_tizen> 3 </since_tizen>
63 public bool IsRequestInProgress
67 return Interop.Manager.IsRequestInProgress(_managerHandle);
72 /// Authorizes the client with access toekn / authorizaion code in Implicit and Authorization Code grant flows respectively.
74 /// <since_tizen> 3 </since_tizen>
75 /// <see cref="CodeGrantAuthorizer.AuthorizeAsync(AuthorizationRequest)"/>
76 /// <see cref="ImplicitGrantAuthorizer.AuthorizeAsync(AuthorizationRequest)"/>
77 /// <param name="request">An authorization request</param>
78 /// <returns> The authorization response from server</returns>
79 public virtual Task<AuthorizationResponse> AuthorizeAsync(AuthorizationRequest request)
81 throw new NotImplementedException();
85 /// Gets the access token in OAuth2 supported grant flows except Implicit Grant flow.
87 /// <since_tizen> 3 </since_tizen>
88 /// <see cref="CodeGrantAuthorizer.AuthorizeAsync(AuthorizationRequest)"/>
89 /// <see cref="ImplicitGrantAuthorizer.AuthorizeAsync(AuthorizationRequest)"/>
90 /// <param name="request">A token request</param>
91 /// <returns>The response from server</returns>
92 public virtual Task<TokenResponse> GetAccessTokenAsync(TokenRequest request)
94 throw new NotImplementedException();
98 /// Releases any unmanaged resources used by this object.
100 /// <since_tizen> 3 </since_tizen>
101 public void Dispose()
104 GC.SuppressFinalize(this);
108 /// Retrieves access token using a refresh token.
110 /// <since_tizen> 3 </since_tizen>
111 /// <param name="request">Request containing refresh token</param>
112 /// <returns>The response containing access token.</returns>
113 /// <privilege>http://tizen.org/privilege/internet</privilege>
114 /// <exception cref="ArgumentException">Thrown when method failed due to invalid argumets</exception>
115 /// <exception cref="OAuth2Exception">Thrown when method fails due to server error</exception>
116 public virtual async Task<TokenResponse> RefreshAccessTokenAsync(RefreshTokenRequest request)
118 IntPtr requestHandle = GetRequestHandle(request);
119 return await Task.Run(() => GetRefreshToken(requestHandle));
122 private TokenResponse GetRefreshToken(IntPtr requestHandle)
124 int ret = (int)OAuth2Error.None;
125 IntPtr error = IntPtr.Zero;
126 TokenResponse response = null;
127 Interop.Manager.Oauth2RefreshTokenCallback accessTokenCb = (IntPtr responseHandle, IntPtr usrData) =>
129 Interop.Response.GetError(responseHandle, out error);
130 if (error != IntPtr.Zero)
132 Log.Error(ErrorFactory.LogTag, "Error occured");
137 ret = Interop.Response.GetAccessToken(responseHandle, out accessToken);
138 if (ret != (int)OAuth2Error.None)
140 Log.Error(ErrorFactory.LogTag, "Interop failed");
141 throw ErrorFactory.GetException(ret);
145 ret = Interop.Response.GetTokenType(responseHandle, out tokenType);
146 if (ret != (int)OAuth2Error.None)
148 Log.Error(ErrorFactory.LogTag, "Failed to get token type");
152 ret = Interop.Response.GetExpiresIn(responseHandle, out expiresIn);
153 if (ret != (int)OAuth2Error.None)
155 Log.Error(ErrorFactory.LogTag, "Failed to get expires in");
159 ret = Interop.Response.GetRefreshToken(responseHandle, out refreshToken);
160 if (ret != (int)OAuth2Error.None)
162 Log.Error(ErrorFactory.LogTag, "Interop failed");
163 throw ErrorFactory.GetException(ret);
167 ret = Interop.Response.GetScope(responseHandle, out scope);
168 if (ret != (int)OAuth2Error.None)
170 Log.Error(ErrorFactory.LogTag, "Failed to get scope");
173 IEnumerable<string> scopes = (scope == IntPtr.Zero) ? null : Marshal.PtrToStringAnsi(scope)?.Split(' ');
175 var token = new AccessToken();
176 token.Token = (accessToken == IntPtr.Zero) ? null : Marshal.PtrToStringAnsi(accessToken);
177 token.TokenType = (tokenType == IntPtr.Zero) ? null : Marshal.PtrToStringAnsi(tokenType);
178 token.Scope = scopes;
179 token.ExpiresIn = expiresIn;
181 response = new TokenResponse(responseHandle);
182 response.AccessToken = token;
183 response.RefreshToken = (refreshToken == IntPtr.Zero) ? null : new RefreshToken() { Token = Marshal.PtrToStringAnsi(refreshToken) };
187 ret = Interop.Manager.RefreshAccessToken(_managerHandle, requestHandle, accessTokenCb, IntPtr.Zero);
188 Interop.Request.Destroy(requestHandle);
189 if (ret != (int)OAuth2Error.None || error != IntPtr.Zero)
191 if (error != IntPtr.Zero)
193 throw ErrorFactory.GetException(error);
197 Log.Error(ErrorFactory.LogTag, "Interop failed");
198 throw ErrorFactory.GetException(ret);
206 /// Releases any unmanaged resources used by this object. Can also dispose any other disposable objects.
208 /// <since_tizen> 3 </since_tizen>
209 /// <param name="disposing">If true, disposes any disposable objects. If false, does not dispose disposable objects.</param>
210 protected virtual void Dispose(bool disposing)
217 // Free managed objects
220 Interop.Manager.Destroy(_managerHandle);
224 // Fill device request handle for refreshing access token
225 internal IntPtr GetRequestHandle(RefreshTokenRequest request)
227 IntPtr requestHandle;
228 int ret = Interop.Request.Create(out requestHandle);
229 if (ret != (int)OAuth2Error.None)
231 Log.Error(ErrorFactory.LogTag, "Interop failed");
232 throw ErrorFactory.GetException(ret);
235 ret = Interop.Request.SetRefreshTokenUrl(requestHandle, request.TokenEndpoint.ToString());
236 if (ret != (int)OAuth2Error.None)
238 Log.Error(ErrorFactory.LogTag, "Interop failed");
239 throw ErrorFactory.GetException(ret);
242 ret = Interop.Request.SetGrantType(requestHandle, Interop.GrantType.Refresh);
243 if (ret != (int)OAuth2Error.None)
245 Log.Error(ErrorFactory.LogTag, "Interop failed");
246 throw ErrorFactory.GetException(ret);
249 ret = Interop.Request.SetRefreshToken(requestHandle, request.RefreshToken);
250 if (ret != (int)OAuth2Error.None)
252 Log.Error(ErrorFactory.LogTag, "Interop failed");
253 throw ErrorFactory.GetException(ret);
256 if (request.ClientSecrets.Id != null)
258 ret = Interop.Request.SetClientId(requestHandle, request.ClientSecrets.Id);
259 if (ret != (int)OAuth2Error.None)
261 Log.Error(ErrorFactory.LogTag, "Interop failed");
262 throw ErrorFactory.GetException(ret);
266 if (request.ClientSecrets.Secret != null)
268 ret = Interop.Request.SetClientSecret(requestHandle, request.ClientSecrets.Secret);
269 if (ret != (int)OAuth2Error.None)
271 Log.Error(ErrorFactory.LogTag, "Interop failed");
272 throw ErrorFactory.GetException(ret);
276 if (request.Scopes != null)
278 string scope = string.Join(" ", request.Scopes);
279 ret = Interop.Request.SetScope(requestHandle, scope);
280 if (ret != (int)OAuth2Error.None)
282 Log.Error(ErrorFactory.LogTag, "Interop failed");
283 throw ErrorFactory.GetException(ret);
287 ret = Interop.Request.SetClientAuthenticationType(requestHandle, (int)request.AuthenticationScheme);
288 if (ret != (int)OAuth2Error.None)
290 Log.Error(ErrorFactory.LogTag, "Interop failed");
291 throw ErrorFactory.GetException(ret);
294 return requestHandle;
297 internal TokenResponse GetAccessToken(IntPtr requestHandle)
299 int ret = (int)OAuth2Error.None;
300 IntPtr error = IntPtr.Zero;
301 TokenResponse response = null;
302 Interop.Manager.Oauth2TokenCallback accessTokenCb = (IntPtr responseHandle, IntPtr usrData) =>
304 if (responseHandle == IntPtr.Zero)
306 Log.Error(ErrorFactory.LogTag, "Error occured");
307 throw (new ArgumentNullException());
310 Interop.Response.GetError(responseHandle, out error);
311 if (error != IntPtr.Zero)
313 Log.Error(ErrorFactory.LogTag, "Server Error occured");
317 IntPtr accessToken = IntPtr.Zero;
318 ret = Interop.Response.GetAccessToken(responseHandle, out accessToken);
319 if (ret != (int)OAuth2Error.None)
321 Log.Error(ErrorFactory.LogTag, "Failed to get access token");
322 throw ErrorFactory.GetException(ret);
326 ret = Interop.Response.GetTokenType(responseHandle, out tokenType);
327 if (ret != (int)OAuth2Error.None)
329 Log.Debug(ErrorFactory.LogTag, "TokenType can't be found");
333 ret = Interop.Response.GetExpiresIn(responseHandle, out expiresIn);
334 if (ret != (int)OAuth2Error.None)
336 Log.Debug(ErrorFactory.LogTag, "ExpiresIn can't be found");
340 ret = Interop.Response.GetRefreshToken(responseHandle, out refreshToken);
341 if (ret != (int)OAuth2Error.None)
343 Log.Debug(ErrorFactory.LogTag, "Refresh Token can't be found");
347 ret = Interop.Response.GetScope(responseHandle, out scope);
348 if (ret != (int)OAuth2Error.None)
350 Log.Debug(ErrorFactory.LogTag, "Scope can't be found");
354 ret = Interop.Response.GetState(responseHandle, out state);
355 if (ret != (int)OAuth2Error.None)
357 Log.Debug(ErrorFactory.LogTag, "State can't be found");
360 IEnumerable<string> scopes = (scope == IntPtr.Zero) ? null : Marshal.PtrToStringAnsi(scope)?.Split(' ');
362 var token = new AccessToken();
363 token.Token = (accessToken == IntPtr.Zero)? null : Marshal.PtrToStringAnsi(accessToken);
364 token.TokenType = (tokenType == IntPtr.Zero) ? null : Marshal.PtrToStringAnsi(tokenType);
365 token.Scope = scopes;
366 token.ExpiresIn = expiresIn;
368 response = new TokenResponse(responseHandle);
369 response.AccessToken = token;
370 response.State = (state == IntPtr.Zero) ? null : Marshal.PtrToStringAnsi(state);
371 response.RefreshToken = (refreshToken == IntPtr.Zero) ? null : new RefreshToken() { Token = Marshal.PtrToStringAnsi(refreshToken) };
375 ret = Interop.Manager.RequestToken(_managerHandle, requestHandle, accessTokenCb, IntPtr.Zero);
376 Interop.Request.Destroy(requestHandle);
377 if (ret != (int)OAuth2Error.None || error != IntPtr.Zero)
379 if (error != IntPtr.Zero)
381 throw ErrorFactory.GetException(error);
385 Log.Error(ErrorFactory.LogTag, "Interop failed");
386 throw ErrorFactory.GetException(ret);
393 internal TokenResponse GetAccessTokenByCode(IntPtr requestHandle)
395 int ret = (int)OAuth2Error.None;
396 IntPtr error = IntPtr.Zero;
397 TokenResponse response = null;
398 Interop.Manager.Oauth2AccessTokenCallback accessTokenCb = (IntPtr responseHandle, IntPtr usrData) =>
400 if (responseHandle == IntPtr.Zero)
402 Log.Error(ErrorFactory.LogTag, "Error occured");
403 throw (new ArgumentNullException());
406 Interop.Response.GetError(responseHandle, out error);
407 if (error != IntPtr.Zero)
409 Log.Error(ErrorFactory.LogTag, "Server Error occured");
413 IntPtr accessToken = IntPtr.Zero;
414 ret = Interop.Response.GetAccessToken(responseHandle, out accessToken);
415 if (ret != (int)OAuth2Error.None)
417 Log.Error(ErrorFactory.LogTag, "Failed to get access token");
418 throw ErrorFactory.GetException(ret);
422 ret = Interop.Response.GetTokenType(responseHandle, out tokenType);
423 if (ret != (int)OAuth2Error.None)
425 Log.Debug(ErrorFactory.LogTag, "TokenType can't be found");
429 ret = Interop.Response.GetExpiresIn(responseHandle, out expiresIn);
430 if (ret != (int)OAuth2Error.None)
432 Log.Debug(ErrorFactory.LogTag, "ExpiresIn can't be found");
436 ret = Interop.Response.GetRefreshToken(responseHandle, out refreshToken);
437 if (ret != (int)OAuth2Error.None)
439 Log.Debug(ErrorFactory.LogTag, "Refresh Token can't be found");
443 ret = Interop.Response.GetScope(responseHandle, out scope);
444 if (ret != (int)OAuth2Error.None)
446 Log.Debug(ErrorFactory.LogTag, "Scope can't be found");
450 ret = Interop.Response.GetState(responseHandle, out state);
451 if (ret != (int)OAuth2Error.None)
453 Log.Debug(ErrorFactory.LogTag, "State can't be found");
456 IEnumerable<string> scopes = (scope == IntPtr.Zero) ? null : Marshal.PtrToStringAnsi(scope)?.Split(' ');
458 var token = new AccessToken();
459 token.Token = (accessToken == IntPtr.Zero) ? null : Marshal.PtrToStringAnsi(accessToken);
460 token.TokenType = (tokenType == IntPtr.Zero) ? null : Marshal.PtrToStringAnsi(tokenType);
461 token.Scope = scopes;
462 token.ExpiresIn = expiresIn;
464 response = new TokenResponse(responseHandle);
465 response.AccessToken = token;
466 response.State = (state == IntPtr.Zero) ? null : Marshal.PtrToStringAnsi(state);
467 response.RefreshToken = (refreshToken == IntPtr.Zero) ? null : new RefreshToken() { Token = Marshal.PtrToStringAnsi(refreshToken) };
471 ret = Interop.Manager.RequestAccessToken(_managerHandle, requestHandle, accessTokenCb, IntPtr.Zero);
472 Interop.Request.Destroy(requestHandle);
473 if (ret != (int)OAuth2Error.None || error != IntPtr.Zero)
475 if (error != IntPtr.Zero)
477 throw ErrorFactory.GetException(error);
481 Log.Error(ErrorFactory.LogTag, "Interop failed : " + ret);
482 throw ErrorFactory.GetException(ret);