Advertisement
architekt909

Auth0Client.cs

Mar 10th, 2018
543
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 9.98 KB | None | 0 0
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Reflection;
  4. using System.Text;
  5. using System.Threading.Tasks;
  6. using IdentityModel.OidcClient.Browser;
  7. using IdentityModel.OidcClient;
  8. using IdentityModel.OidcClient.Results;
  9.  
  10. #if __IOS__
  11. using SafariServices;
  12. using WebKit;
  13. using CoreGraphics;
  14. #endif
  15.  
  16. namespace Auth0.OidcClient
  17. {
  18.     public class Auth0Client
  19.     {
  20.         private readonly Auth0ClientOptions _options;
  21.         private readonly IdentityModel.OidcClient.OidcClient _oidcClient;
  22.  
  23.         /// <summary>
  24.         /// Creates a new instance of the Auth0 OIDC Client.
  25.         /// </summary>
  26.         /// <param name="options">The <see cref="Auth0ClientOptions"/> specifying the configuration for the Auth0 OIDC Client.</param>
  27.         public Auth0Client(Auth0ClientOptions options)
  28.         {
  29.             _options = options;
  30.  
  31.             var authority = $"https://{options.Domain}";
  32. #if __ANDROID__
  33.             string packageName = options.Activity.Application.ApplicationInfo.PackageName;
  34. #endif
  35.  
  36. #if __IOS__
  37.             var redirectUri = $"{Foundation.NSBundle.MainBundle.BundleIdentifier}://{options.Domain}/ios/{Foundation.NSBundle.MainBundle.BundleIdentifier}/callback";
  38.             IBrowser browser;
  39.             if (options.UseWKWebView)
  40.                 browser = new PlatformWKWebView(options.Controller, redirectUri);
  41.             else
  42.                 browser = new PlatformWebView(options.Controller);
  43. #endif
  44.  
  45.             var oidcClientOptions = new OidcClientOptions
  46.             {
  47.                 Authority = authority,
  48.                 ClientId = options.ClientId,
  49.                 ClientSecret = options.ClientSecret,
  50.                 Scope = options.Scope,
  51.                 LoadProfile = options.LoadProfile,
  52. #if __IOS__
  53.                 RedirectUri = redirectUri,
  54.                 Browser = browser,
  55. #elif __ANDROID__
  56.                 RedirectUri = options.RedirectUri ?? $"{packageName}://{options.Domain}/android/{packageName}/callback".ToLower(),
  57.                 Browser = new PlatformWebView(options.Activity),
  58. #elif WINDOWS_UWP
  59.                 RedirectUri = Windows.Security.Authentication.Web.WebAuthenticationBroker.GetCurrentApplicationCallbackUri().AbsoluteUri,
  60.                 Browser = options.Browser ?? new PlatformWebView(),
  61. #else
  62.                 RedirectUri = options.RedirectUri ?? $"https://{options.Domain}/mobile",
  63.                 Browser = options.Browser ?? new PlatformWebView(),
  64. #endif
  65.                 Flow = OidcClientOptions.AuthenticationFlow.AuthorizationCode,
  66. #if WINDOWS_UWP
  67.                 ResponseMode = OidcClientOptions.AuthorizeResponseMode.FormPost,
  68. #else
  69.                 ResponseMode = OidcClientOptions.AuthorizeResponseMode.Redirect,
  70. #endif
  71.                 Policy =
  72.                 {
  73.                     RequireAuthorizationCodeHash = false,
  74.                     RequireAccessTokenHash = false
  75.                 }
  76.             };
  77.             _oidcClient = new IdentityModel.OidcClient.OidcClient(oidcClientOptions);          
  78.         }
  79.  
  80. #if __IOS__
  81.         private PlatformWKWebView PlatformWKWebView => (PlatformWKWebView)_oidcClient.Options.Browser;
  82.  
  83.         // Only used when UseWKWebView is true: will automatically close the view after successfully logging in or canceling
  84.         public void SetAutoClose(bool close) => PlatformWKWebView.AutoClose = close;       
  85.  
  86.         // Only used when UseWKWebView is true: Sets a handler to be called in the event of user cancelation. Optional.
  87.         public void SetOnCancel(Action<WKWebView> onCancel) => PlatformWKWebView.OnCancel = onCancel;      
  88.  
  89.         // Only used when UseWKWebView is true: Sets a handler to be called in the event of user cancelation. Optional.
  90.         public void SetOnSuccess(Action<WKWebView> onSuccess) => PlatformWKWebView.OnSuccess = onSuccess;
  91.  
  92.         // If true, prevents the web view from bouncing if you scroll and release
  93.         public void DisableBouncing(bool disable) => PlatformWKWebView.DisableBouncing = disable;
  94.  
  95.         // If true, prevents the web view from being able to be zoomed in. This will also prevent zooming when the user types in a text field
  96.         public void DisableZooming(bool disable) => PlatformWKWebView.DisableZooming = disable;
  97.  
  98.         // If true, prevents the web view from being able to scroll at all
  99.         public void DisableScrolling(bool disable) => PlatformWKWebView.DisableScrolling = disable;
  100.  
  101.         // Sets a custom frame for the login window (only if UseWKWebView is true). If not set, uses the controller's view frame.
  102.         public void SetWKWebViewFrame(CGRect frame) => PlatformWKWebView.WKWebViewFrame = frame;
  103.  
  104.         /*
  105.             If you want to be able to catch the user clicking the "X" aka close button on your login screen, so you can detect cancelation,
  106.             you need to do a couple things.
  107.             1. Edit your login page javascript to set the lock widget to allow closing.
  108.                 If you're using a hosted page just click "Hosted Pages" from the dashboard, select
  109.                 "Customize Login Page", then edit the document. In the lock instantiation, add "closable: true". If you have a default HTML
  110.                 implementation, you could do this after the "auth: {...}" setting, or wherever you want.
  111.             2. Add a message to be posted when the lock close button is pressed. If you're using a hosted page with the default HTML implementation, do this after
  112.                 the instantiation of lock. I.e. after the large "var lock = new Auth0Lock(....":
  113.        
  114.                 lock.on('hide', () =>
  115.                 {      
  116.                     webkit.messageHandlers.callbackHandler.postMessage("hide");
  117.                 });
  118.  
  119.             There's 2 important things to note here. The first is "callbackHandler". You can call this whatever you want.
  120.             The second is the string "hide" in the postMessage(...) call. You can make this whatever you want as well.
  121.             Note: don't change the word 'hide' specified as the lock.on(...) first parameter: Auth0 lock will emit this when the X button is pressed.
  122.  
  123.             If you don't set these two properties, and/or you don't edit your hosted lock page, then we won't be able respond to the user closing the window.
  124.          */
  125.         public void SetOnHideCallbackHandler(string callbackHandler) => PlatformWKWebView.JavascriptCallbackHandlerName = callbackHandler;
  126.         public void SetOnHideMessageName(string messageName) => PlatformWKWebView.JavascriptOnLockHideEventName = messageName;
  127. #endif
  128.  
  129.         private Dictionary<string, string> AppendTelemetry(object values)
  130.         {
  131.             var dictionary = ObjectToDictionary(values);
  132.  
  133.             if (_options.EnableTelemetry)
  134.                 dictionary.Add("auth0Client", CreateTelemetry());
  135.  
  136.             return dictionary;
  137.         }
  138.  
  139.         private string CreateTelemetry()
  140.         {
  141. #if __ANDROID__
  142.             string platform = "xamarin-android";
  143. #elif __IOS__
  144.             string platform = "xamarin-ios";
  145. #elif WINFORMS
  146.             string platform = "winforms";
  147. #elif WPF
  148.             string platform = "wpf";
  149. #elif WINDOWS_UWP
  150.             var platform = "uwp";
  151. #endif
  152.             var version = GetType().GetTypeInfo().Assembly.GetCustomAttribute<AssemblyFileVersionAttribute>()
  153.                 .Version;
  154.  
  155.             var telemetryString = $"{{\"name\":\"oidc-net\",\"version\":\"{version}\",\"platform\":\"{platform}\"}}";
  156.             var telemetryBytes = Encoding.UTF8.GetBytes(telemetryString);
  157.  
  158.             return Convert.ToBase64String(telemetryBytes);
  159.         }
  160.  
  161.         /// <summary>
  162.         /// Launches a browser to log the user in.
  163.         /// </summary>
  164.         /// <param name="extraParameters">Any extra parameters that need to be passed to the authorization endpoint.</param>
  165.         /// <returns></returns>
  166.         public Task<LoginResult> LoginAsync(object extraParameters = null)
  167.         {
  168. #pragma warning disable CS0618 // Type or member is obsolete
  169.             return _oidcClient.LoginAsync(extraParameters: AppendTelemetry(extraParameters));
  170. #pragma warning restore CS0618 // Type or member is obsolete
  171.         }
  172.  
  173.         private Dictionary<string, string> ObjectToDictionary(object values)
  174.         {
  175.             var dictionary = values as Dictionary<string, string>;
  176.             if (dictionary != null)
  177.                 return dictionary;
  178.  
  179.             dictionary = new Dictionary<string, string>();
  180.             if (values != null)
  181.                 foreach (var prop in values.GetType().GetRuntimeProperties())
  182.                 {
  183.                     var value = prop.GetValue(values) as string;
  184.                     if (!string.IsNullOrEmpty(value))
  185.                         dictionary.Add(prop.Name, value);
  186.                 }
  187.  
  188.             return dictionary;
  189.         }
  190.  
  191.         /// <summary>
  192.         /// Generates an <see cref="AuthorizeState"/> containing the URL, state, nonce and code challenge which can
  193.         /// be used to redirect the user to the authorization URL, and subsequently process any response by calling
  194.         /// the <see cref="ProcessResponseAsync"/> method.
  195.         /// </summary>
  196.         /// <param name="extraParameters"></param>
  197.         /// <returns></returns>
  198.         public Task<AuthorizeState> PrepareLoginAsync(object extraParameters = null)
  199.         {
  200.             return _oidcClient.PrepareLoginAsync(AppendTelemetry(extraParameters));
  201.         }
  202.  
  203.         /// <summary>
  204.         /// Process the response from the Auth0 redirect URI
  205.         /// </summary>
  206.         /// <param name="data">The data containing the full redirect URI.</param>
  207.         /// <param name="state">The <see cref="AuthorizeState"/> which was generated when the <see cref="PrepareLoginAsync"/>
  208.         /// method was called.</param>
  209.         /// <returns></returns>
  210.         public Task<LoginResult> ProcessResponseAsync(string data, AuthorizeState state)
  211.         {
  212.             return _oidcClient.ProcessResponseAsync(data, state);
  213.         }
  214.  
  215.         /// <summary>
  216.         /// Generates a new set of tokens based on a refresh token.
  217.         /// </summary>
  218.         /// <param name="refreshToken">The refresh token which was issued during the authorization flow, or subsequent
  219.         /// calls to <see cref="RefreshTokenAsync"/>.</param>
  220.         /// <returns></returns>
  221.         public Task<RefreshTokenResult> RefreshTokenAsync(string refreshToken)
  222.         {
  223.             return _oidcClient.RefreshTokenAsync(refreshToken);
  224.         }
  225.     }
  226. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement