Release 4.0.0-preview1-00051
[platform/core/csapi/tizenfx.git] / src / Tizen.Account.OAuth2 / Tizen.Account.OAuth2 / CodeGrantAuthorizer.cs
1 /*
2  * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
3  *
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
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16
17 using System;
18 using System.Threading.Tasks;
19 using System.Runtime.InteropServices;
20 using System.Collections.Generic;
21
22 namespace Tizen.Account.OAuth2
23 {
24     /// <summary>
25     /// The CodeGrantAuthorizer is used to obtain access tokens and refresh tokens using Authorization Code Grant flow as described at https://tools.ietf.org/html/rfc6749#section-4.1
26     /// </summary>
27     /// <since_tizen> 3 </since_tizen>
28     public class CodeGrantAuthorizer : Authorizer
29     {
30         /// <summary>
31         /// The constructor
32         /// </summary>
33         /// <since_tizen> 3 </since_tizen>
34         public CodeGrantAuthorizer()
35         {
36
37         }
38
39         /// <summary>
40         /// Retrieves authorization code asynchronously. The authroization request parameters should be as defined in https://tools.ietf.org/html/rfc6749#section-4.1.1
41         /// </summary>
42         /// <since_tizen> 3 </since_tizen>
43         /// <param name="request">The authorization request <see cref="CodeGrantAuthorizationRequest"/></param>
44         /// <returns>The response containing authorization code.</returns>
45         /// <privilege>http://tizen.org/privilege/internet</privilege>
46         /// <exception cref="ArgumentException">Thrown when method failed due to invalid argumets</exception>
47         /// <exception cref="OAuth2Exception">Thrown when method fails due to server error</exception>
48         public override async Task<AuthorizationResponse> AuthorizeAsync(AuthorizationRequest request)
49         {
50             IntPtr requestHandle = GetRequestHandle(request as CodeGrantAuthorizationRequest);
51             return await Task.Run(() => GetAuthorizationResponse(requestHandle));
52         }
53
54         /// <summary>
55         /// Retrieves access token by exchanging authorization code received using <see cref="AuthorizeAsync(AuthorizationRequest)"/>.
56         /// The authroization request parameters should be as defined in https://tools.ietf.org/html/rfc6749#section-4.1.3
57         /// </summary>
58         /// <since_tizen> 3 </since_tizen>
59         /// <param name="request">The token request <see cref="CodeGrantTokenRequest"/></param>
60         /// <returns>The response containing access token.</returns>
61         /// <privilege>http://tizen.org/privilege/internet</privilege>
62         /// <exception cref="ArgumentException">Thrown when method failed due to invalid argumets</exception>
63         /// <exception cref="OAuth2Exception">Thrown when method fails due to server error</exception>
64         public override async Task<TokenResponse> GetAccessTokenAsync(TokenRequest request)
65         {
66             IntPtr requestHandle = GetRequestHandle(request as CodeGrantTokenRequest);
67             return await Task.Run(() => GetAccessTokenByCode(requestHandle) );
68         }
69
70         /// <summary>
71         /// Clears the cookies
72         /// </summary>
73         /// <since_tizen> 3 </since_tizen>
74         public void ClearCookies()
75         {
76             int ret = (int)OAuth2Error.None;
77             ret = Interop.Manager.ClearCookies(_managerHandle);
78             if (ret != (int)OAuth2Error.None)
79             {
80                 Log.Error(ErrorFactory.LogTag, "Interop failed");
81                 throw ErrorFactory.GetException(ret);
82             }
83         }
84
85         /// <summary>
86         /// Clear the cache
87         /// </summary>
88         /// <since_tizen> 3 </since_tizen>
89         public void ClearCache()
90         {
91             int ret = (int)OAuth2Error.None;
92             ret = Interop.Manager.ClearCache(_managerHandle);
93             if (ret != (int)OAuth2Error.None)
94             {
95                 Log.Error(ErrorFactory.LogTag, "Interop failed");
96                 throw ErrorFactory.GetException(ret);
97             }
98         }
99
100         // Fill device request handle for Authorization code grant
101         private IntPtr GetRequestHandle(CodeGrantAuthorizationRequest request)
102         {
103             if (request == null)
104             {
105                 Log.Error(ErrorFactory.LogTag, "Invalid request or request is null");
106                 throw ErrorFactory.GetException((int)OAuth2Error.InvalidParameter);
107             }
108
109             IntPtr requestHandle;
110             int ret = Interop.Request.Create(out requestHandle);
111             if (ret != (int)OAuth2Error.None)
112             {
113                 Log.Error(ErrorFactory.LogTag, "Interop failed");
114                 throw ErrorFactory.GetException(ret);
115             }
116
117             ret = Interop.Request.SetAuthEndPointUrl(requestHandle, request.AuthorizationEndpoint.ToString());
118             if (ret != (int)OAuth2Error.None)
119             {
120                 Log.Error(ErrorFactory.LogTag, "Interop failed");
121                 throw ErrorFactory.GetException(ret);
122             }
123
124             ret = Interop.Request.SetResponseType(requestHandle, Interop.ResponseType.Code);
125             if (ret != (int)OAuth2Error.None)
126             {
127                 Log.Error(ErrorFactory.LogTag, "Interop failed");
128                 throw ErrorFactory.GetException(ret);
129             }
130
131             if (request.ClientSecrets.Id != null)
132             {
133                 ret = Interop.Request.SetClientId(requestHandle, request.ClientSecrets.Id);
134                 if (ret != (int)OAuth2Error.None)
135                 {
136                     Log.Error(ErrorFactory.LogTag, "Interop failed");
137                     throw ErrorFactory.GetException(ret);
138                 }
139             }
140
141             if (request.ClientSecrets.Secret != null)
142             {
143                 ret = Interop.Request.SetClientSecret(requestHandle, request.ClientSecrets.Secret);
144                 if (ret != (int)OAuth2Error.None)
145                 {
146                     Log.Error(ErrorFactory.LogTag, "Interop failed");
147                     throw ErrorFactory.GetException(ret);
148                 }
149             }
150
151             if (request.RedirectionEndPoint != null)
152             {
153                 ret = Interop.Request.SetRedirectionUrl(requestHandle, request.RedirectionEndPoint.OriginalString);
154                 if (ret != (int)OAuth2Error.None)
155                 {
156                     Log.Error(ErrorFactory.LogTag, "Interop failed");
157                     throw ErrorFactory.GetException(ret);
158                 }
159             }
160
161             if (request.Scopes != null)
162             {
163                 string scope = string.Join(" ", request.Scopes);
164                 ret = Interop.Request.SetScope(requestHandle, scope);
165                 if (ret != (int)OAuth2Error.None)
166                 {
167                     Log.Error(ErrorFactory.LogTag, "Interop failed");
168                     throw ErrorFactory.GetException(ret);
169                 }
170             }
171
172             if (request.State != null)
173             {
174                 ret = Interop.Request.SetState(requestHandle, request.State);
175                 if (ret != (int)OAuth2Error.None)
176                 {
177                     Log.Error(ErrorFactory.LogTag, "Interop failed");
178                     throw ErrorFactory.GetException(ret);
179                 }
180             }
181
182             if (request.CustomData != null)
183             {
184                 foreach( var item in request.CustomData)
185                 {
186                     ret = Interop.Request.AddCustomData(requestHandle, item.Key, item.Value);
187                     if (ret != (int)OAuth2Error.None)
188                     {
189                         Log.Error(ErrorFactory.LogTag, "Interop failed");
190                         throw ErrorFactory.GetException(ret);
191                     }
192                 }
193             }
194
195             return requestHandle;
196         }
197
198         // Fill device request handle for access token
199         private IntPtr GetRequestHandle(CodeGrantTokenRequest request)
200         {
201             if (request == null)
202             {
203                 Log.Error(ErrorFactory.LogTag, "Invalid request or request is null");
204                 throw ErrorFactory.GetException((int)OAuth2Error.InvalidParameter);
205             }
206
207             IntPtr requestHandle;
208             int ret = Interop.Request.Create(out requestHandle);
209             if (ret != (int)OAuth2Error.None)
210             {
211                 Log.Error(ErrorFactory.LogTag, "Interop failed");
212                 throw ErrorFactory.GetException(ret);
213             }
214
215             ret = Interop.Request.SetGrantType(requestHandle, Interop.GrantType.AuthCode);
216             if (ret != (int)OAuth2Error.None)
217             {
218                 Log.Error(ErrorFactory.LogTag, "Interop failed");
219                 throw ErrorFactory.GetException(ret);
220             }
221
222             ret = Interop.Request.SetAuthorizationCode(requestHandle, request.Code);
223             if (ret != (int)OAuth2Error.None)
224             {
225                 Log.Error(ErrorFactory.LogTag, "Interop failed");
226                 throw ErrorFactory.GetException(ret);
227             }
228
229             ret = Interop.Request.SetTokenEndPointUrl(requestHandle, request.TokenEndpoint.ToString());
230             if (ret != (int)OAuth2Error.None)
231             {
232                 Log.Error(ErrorFactory.LogTag, "Interop failed");
233                 throw ErrorFactory.GetException(ret);
234             }
235
236             ret = Interop.Request.SetRedirectionUrl(requestHandle, request.RedirectionEndPoint.ToString());
237             if (ret != (int)OAuth2Error.None)
238             {
239                 Log.Error(ErrorFactory.LogTag, "Interop failed");
240                 throw ErrorFactory.GetException(ret);
241             }
242
243             ret = Interop.Request.SetClientId(requestHandle, request.ClientSecrets.Id);
244             if (ret != (int)OAuth2Error.None)
245             {
246                 Log.Error(ErrorFactory.LogTag, "Interop failed");
247                 throw ErrorFactory.GetException(ret);
248             }
249
250             if (request.ClientSecrets.Secret != null)
251             {
252                 ret = Interop.Request.SetClientSecret(requestHandle, request.ClientSecrets.Secret);
253                 if (ret != (int)OAuth2Error.None)
254                 {
255                     Log.Error(ErrorFactory.LogTag, "Interop failed");
256                     throw ErrorFactory.GetException(ret);
257                 }
258             }
259
260             if (request.CustomData != null)
261             {
262                 foreach (var item in request.CustomData)
263                 {
264                     ret = Interop.Request.AddCustomData(requestHandle, item.Key, item.Value);
265                     if (ret != (int)OAuth2Error.None)
266                     {
267                         Log.Error(ErrorFactory.LogTag, "Interop failed");
268                         throw ErrorFactory.GetException(ret);
269                     }
270                 }
271             }
272
273             ret = Interop.Request.SetClientAuthenticationType(requestHandle, (int)request.AuthenticationScheme);
274             if (ret != (int)OAuth2Error.None)
275             {
276                 Log.Error(ErrorFactory.LogTag, "Interop failed");
277                 throw ErrorFactory.GetException(ret);
278             }
279
280             return requestHandle;
281         }
282
283         private AuthorizationResponse GetAuthorizationResponse(IntPtr requestHandle)
284         {
285             AuthorizationResponse response = null;
286             int ret = (int)OAuth2Error.None;
287             IntPtr error = IntPtr.Zero;
288
289             Interop.Manager.Oauth2AuthGrantCallback authGrantCb = (IntPtr responseHandle, IntPtr usrData) =>
290             {
291                 if (responseHandle == IntPtr.Zero)
292                 {
293                     Log.Error(ErrorFactory.LogTag, "Error occured");
294                     throw (new ArgumentNullException());
295                 }
296
297                 Interop.Response.GetError(responseHandle, out error);
298                 if (error == IntPtr.Zero)
299                 {
300                     Log.Warn(ErrorFactory.LogTag, "Error occured");
301                     throw ErrorFactory.GetException(error);
302                 }
303                 else
304                 {
305                     IntPtr authorizationCode;
306                     ret = Interop.Response.GetAuthorizationCode(responseHandle, out authorizationCode);
307                     if (ret != (int)OAuth2Error.None)
308                     {
309                         Log.Error(ErrorFactory.LogTag, "Interop failed");
310                         throw ErrorFactory.GetException(ret);
311                     }
312
313                     IntPtr state;
314                     ret = Interop.Response.GetState(responseHandle, out state);
315                     if (ret != (int)OAuth2Error.None)
316                     {
317                         Log.Error(ErrorFactory.LogTag, "Interop failed");
318                         throw ErrorFactory.GetException(ret);
319                     }
320
321                     response = new AuthorizationResponse(responseHandle) { Code = Marshal.PtrToStringAnsi(authorizationCode), State = Marshal.PtrToStringAnsi(state) };
322                 }
323             };
324
325             ret = Interop.Manager.RequestAuthorizationGrant(_managerHandle, requestHandle, authGrantCb, IntPtr.Zero);
326             Interop.Request.Destroy(requestHandle);
327             if (ret != (int)OAuth2Error.None || error != IntPtr.Zero)
328             {
329                 if (error != IntPtr.Zero)
330                 {
331                     throw ErrorFactory.GetException(error);
332                 }
333                 else
334                 {
335                     Log.Error(ErrorFactory.LogTag, "Interop failed");
336                     throw ErrorFactory.GetException(ret);
337                 }
338             }
339
340             return response;
341         }
342     }
343 }