Release 4.0.0-preview1-00051
[platform/core/csapi/tizenfx.git] / src / Tizen.Account.OAuth2 / Tizen.Account.OAuth2 / ImplicitGrantAuthorizer.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.Collections.Generic;
19 using System.Runtime.InteropServices;
20 using System.Threading.Tasks;
21
22 namespace Tizen.Account.OAuth2
23 {
24     /// <summary>
25     /// The ImplicitGrantAuthorizer is used to obtain access tokens using Implicit Grant flow as described at https://tools.ietf.org/html/rfc6749#section-4.2
26     /// </summary>
27     /// <since_tizen> 3 </since_tizen>
28     public class ImplicitGrantAuthorizer : Authorizer
29     {
30         /// <summary>
31         /// The constructor
32         /// </summary>
33         /// <since_tizen> 3 </since_tizen>
34         public ImplicitGrantAuthorizer()
35         {
36
37         }
38
39         /// <summary>
40         /// Retrieves access token asynchronously. The authroization request parameters should be as defined in https://tools.ietf.org/html/rfc6749#section-4.2.1
41         /// </summary>
42         /// <since_tizen> 3 </since_tizen>
43         /// <param name="request">The authorization request <see cref="ImplicitGrantAuthorizationRequest"/></param>
44         /// <returns>The response containing access token.</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 new virtual async Task<TokenResponse> AuthorizeAsync(AuthorizationRequest request)
49         {
50             IntPtr requestHandle = GetRequestHandle(request as ImplicitGrantAuthorizationRequest);
51             return await Task.Run(() => GetAuthorizationResponse(requestHandle));
52         }
53
54         /// <summary>
55         /// Access token can be retreived implicitly using <see cref="AuthorizeAsync"/> in this flow.
56         /// </summary>
57         /// <since_tizen> 3 </since_tizen>
58         /// <exception cref="InvalidOperationException">Thrown when the operation is not supported</exception>
59         public override Task<TokenResponse> GetAccessTokenAsync(TokenRequest request)
60         {
61             Log.Error(ErrorFactory.LogTag, "Obtain token directly from authorization grant ");
62             throw new InvalidOperationException();
63         }
64
65         /// <summary>
66         /// Refreshing access token is not supported in this flow.
67         /// </summary>
68         /// <since_tizen> 3 </since_tizen>
69         /// <exception cref="InvalidOperationException">Thrown when the operation is not supported</exception>
70         public override Task<TokenResponse> RefreshAccessTokenAsync(RefreshTokenRequest request)
71         {
72             Log.Error(ErrorFactory.LogTag, "Refesh token is not supported in Implicit Grant flow");
73             throw new InvalidOperationException();
74         }
75
76         private TokenResponse GetAuthorizationResponse(IntPtr requestHandle)
77         {
78             IntPtr error = IntPtr.Zero;
79             TokenResponse response = null;
80             int ret = (int)OAuth2Error.None;
81             Interop.Manager.Oauth2AuthGrantCallback authGrantCb = (IntPtr responseHandle, IntPtr usrData) =>
82             {
83                 if (responseHandle == IntPtr.Zero)
84                 {
85                     Log.Error(ErrorFactory.LogTag, "Error occured");
86                     throw (new ArgumentNullException());
87                 }
88
89                 Interop.Response.GetError(responseHandle, out error);
90                 if (error != IntPtr.Zero)
91                 {
92                     Log.Error(ErrorFactory.LogTag, "Server Error occured");
93                 }
94                 else
95                 {
96                     IntPtr accessToken;
97                     ret = Interop.Response.GetAccessToken(responseHandle, out accessToken);
98                     if (ret != (int)OAuth2Error.None)
99                     {
100                         Log.Error(ErrorFactory.LogTag, "Interop failed");
101                         throw ErrorFactory.GetException(ret);
102                     }
103
104                     IntPtr tokenType;
105                     ret = Interop.Response.GetTokenType(responseHandle, out tokenType);
106                     if (ret != (int)OAuth2Error.None)
107                     {
108                         Log.Error(ErrorFactory.LogTag, "Interop failed");
109                         throw ErrorFactory.GetException(ret);
110                     }
111
112                     long expiresIn;
113                     ret = Interop.Response.GetExpiresIn(responseHandle, out expiresIn);
114                     if (ret != (int)OAuth2Error.None)
115                     {
116                         Log.Error(ErrorFactory.LogTag, "Interop failed");
117                         throw ErrorFactory.GetException(ret);
118                     }
119
120                     IntPtr scope;
121                     ret = Interop.Response.GetScope(responseHandle, out scope);
122                     if (ret != (int)OAuth2Error.None)
123                     {
124                         Log.Error(ErrorFactory.LogTag, "Interop failed");
125                         throw ErrorFactory.GetException(ret);
126                     }
127
128                     IntPtr state;
129                     ret = Interop.Response.GetState(responseHandle, out state);
130                     if (ret != (int)OAuth2Error.None)
131                     {
132                         Log.Error(ErrorFactory.LogTag, "Interop failed");
133                         throw ErrorFactory.GetException(ret);
134                     }
135
136                     IEnumerable<string> scopes = (scope == IntPtr.Zero) ? null : Marshal.PtrToStringAnsi(scope)?.Split(' ');
137
138                     var token = new AccessToken() { Token = Marshal.PtrToStringAnsi(accessToken), ExpiresIn = expiresIn, Scope = scopes, TokenType = Marshal.PtrToStringAnsi(tokenType) };
139                     response = new TokenResponse(responseHandle) { AccessToken = token, State = Marshal.PtrToStringAnsi(state), RefreshToken = null };
140                 }
141             };
142
143             ret = Interop.Manager.RequestAuthorizationGrant(_managerHandle, requestHandle, authGrantCb, IntPtr.Zero);
144             Interop.Request.Destroy(requestHandle);
145             if (ret != (int)OAuth2Error.None || error != IntPtr.Zero)
146             {
147                 if (error != IntPtr.Zero)
148                 {
149                     throw ErrorFactory.GetException(error);
150                 }
151                 else
152                 {
153                     Log.Error(ErrorFactory.LogTag, "Interop failed");
154                     throw ErrorFactory.GetException(ret);
155                 }
156             }
157
158             return response;
159         }
160
161         // Fill device request handle for Authorization code grant
162         private IntPtr GetRequestHandle(ImplicitGrantAuthorizationRequest request)
163         {
164             if (request == null)
165             {
166                 Log.Error(ErrorFactory.LogTag, "Invalid request or request is null");
167                 throw ErrorFactory.GetException((int)OAuth2Error.InvalidParameter);
168             }
169
170             IntPtr requestHandle;
171             int ret = Interop.Request.Create(out requestHandle);
172             if (ret != (int)OAuth2Error.None)
173             {
174                 Log.Error(ErrorFactory.LogTag, "Interop failed");
175                 throw ErrorFactory.GetException(ret);
176             }
177
178             ret = Interop.Request.SetAuthEndPointUrl(requestHandle, request.AuthorizationEndpoint.ToString());
179             if (ret != (int)OAuth2Error.None)
180             {
181                 Log.Error(ErrorFactory.LogTag, "Interop failed");
182                 throw ErrorFactory.GetException(ret);
183             }
184
185             ret = Interop.Request.SetResponseType(requestHandle, Interop.ResponseType.Token);
186             if (ret != (int)OAuth2Error.None)
187             {
188                 Log.Error(ErrorFactory.LogTag, "Interop failed");
189                 throw ErrorFactory.GetException(ret);
190             }
191
192             ret = Interop.Request.SetClientId(requestHandle, request.ClientSecrets.Id);
193             if (ret != (int)OAuth2Error.None)
194             {
195                 Log.Error(ErrorFactory.LogTag, "Interop failed");
196                 throw ErrorFactory.GetException(ret);
197             }
198
199             if (request.RedirectionEndPoint != null)
200             {
201                 ret = Interop.Request.SetRedirectionUrl(requestHandle, request.RedirectionEndPoint.ToString());
202                 if (ret != (int)OAuth2Error.None)
203                 {
204                     Log.Error(ErrorFactory.LogTag, "Interop failed");
205                     throw ErrorFactory.GetException(ret);
206                 }
207             }
208
209             if (request.Scopes != null)
210             {
211                 string scope = string.Join(" ", request.Scopes);
212                 ret = Interop.Request.SetScope(requestHandle, scope);
213                 if (ret != (int)OAuth2Error.None)
214                 {
215                     Log.Error(ErrorFactory.LogTag, "Interop failed");
216                     throw ErrorFactory.GetException(ret);
217                 }
218             }
219
220             if (request.State != null)
221             {
222                 ret = Interop.Request.SetState(requestHandle, request.State);
223                 if (ret != (int)OAuth2Error.None)
224                 {
225                     Log.Error(ErrorFactory.LogTag, "Interop failed");
226                     throw ErrorFactory.GetException(ret);
227                 }
228             }
229
230             if (request.CustomData != null)
231             {
232                 foreach (var item in request.CustomData)
233                 {
234                     ret = Interop.Request.AddCustomData(requestHandle, item.Key, item.Value);
235                     if (ret != (int)OAuth2Error.None)
236                     {
237                         Log.Error(ErrorFactory.LogTag, "Interop failed");
238                         throw ErrorFactory.GetException(ret);
239                     }
240                 }
241             }
242
243             return requestHandle;
244         }
245     }
246 }