Skip to content

Commit

Permalink
Mac now has Native Login support
Browse files Browse the repository at this point in the history
  • Loading branch information
Clancey committed Sep 20, 2016
1 parent 0c91319 commit da72af7
Show file tree
Hide file tree
Showing 8 changed files with 226 additions and 3 deletions.
10 changes: 10 additions & 0 deletions samples/Sample.Mac/AppDelegate.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ public partial class AppDelegate : NSApplicationDelegate
{
MainWindowController mainWindowController;


public AppDelegate()
{
}
Expand All @@ -15,11 +16,20 @@ public override void DidFinishLaunching(NSNotification notification)
{
mainWindowController = new MainWindowController();
mainWindowController.Window.MakeKeyAndOrderFront(this);
NSAppleEventManager.SharedAppleEventManager.SetEventHandler (this, new ObjCRuntime.Selector ("UrlHandleEvent:event:replyEvent"), AEEventClass.Internet, AEEventID.GetUrl);
}

public override void WillTerminate(NSNotification notification)
{
// Insert code here to tear down your application
}

[Export("UrlHandleEvent:event:replyEvent")]
public void UrlHandleEvent (NSAppleEventDescriptor evt, NSAppleEventDescriptor replyEvt)
{
var url = evt.ParamDescriptorForKeyword (AppleEventParameters.DirectObject).StringValue;
SimpleAuth.NativeSafariAuthenticator.ResumeAuth (url);
}

}
}
14 changes: 12 additions & 2 deletions samples/Sample.Mac/Info.plist
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
Expand Down Expand Up @@ -28,6 +28,16 @@
<string>MainMenu</string>
<key>XSAppIconAssets</key>
<string>Resources/Images.xcassets/AppIcons.appiconset</string>

<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleTypeRole</key>
<string>Editor</string>
<key>CFBundleURLSchemes</key>
<array>
<string>com.googleusercontent.apps.CLIENT_ID</string>
</array>
</dict>
</array>
</dict>
</plist>
5 changes: 5 additions & 0 deletions samples/Sample.Mac/Sample.Mac.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,10 @@
<Reference Include="System.Core" />
<Reference Include="Xamarin.Mac" />
<Reference Include="System.Net.Http" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="Newtonsoft.Json">
<HintPath>..\..\packages\Newtonsoft.Json.9.0.1\lib\netstandard1.0\Newtonsoft.Json.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup>
<ImageAsset Include="Resources\Images.xcassets\AppIcons.appiconset\Contents.json" />
Expand All @@ -68,6 +72,7 @@
</ItemGroup>
<ItemGroup>
<None Include="Info.plist" />
<None Include="packages.config" />
</ItemGroup>
<ItemGroup>
<Compile Include="Main.cs" />
Expand Down
26 changes: 26 additions & 0 deletions samples/Sample.Mac/packages.config
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Microsoft.CSharp" version="4.0.1" targetFramework="xamarinmac20" />
<package id="Newtonsoft.Json" version="9.0.1" targetFramework="xamarinmac20" />
<package id="System.Collections" version="4.0.11" targetFramework="xamarinmac20" />
<package id="System.Diagnostics.Debug" version="4.0.11" targetFramework="xamarinmac20" />
<package id="System.Dynamic.Runtime" version="4.0.11" targetFramework="xamarinmac20" />
<package id="System.Globalization" version="4.0.11" targetFramework="xamarinmac20" />
<package id="System.IO" version="4.1.0" targetFramework="xamarinmac20" />
<package id="System.Linq" version="4.1.0" targetFramework="xamarinmac20" />
<package id="System.Linq.Expressions" version="4.1.0" targetFramework="xamarinmac20" />
<package id="System.ObjectModel" version="4.0.12" targetFramework="xamarinmac20" />
<package id="System.Reflection" version="4.1.0" targetFramework="xamarinmac20" />
<package id="System.Reflection.Extensions" version="4.0.1" targetFramework="xamarinmac20" />
<package id="System.Resources.ResourceManager" version="4.0.1" targetFramework="xamarinmac20" />
<package id="System.Runtime" version="4.1.0" targetFramework="xamarinmac20" />
<package id="System.Runtime.Extensions" version="4.1.0" targetFramework="xamarinmac20" />
<package id="System.Runtime.Serialization.Primitives" version="4.1.1" targetFramework="xamarinmac20" />
<package id="System.Text.Encoding" version="4.0.11" targetFramework="xamarinmac20" />
<package id="System.Text.Encoding.Extensions" version="4.0.11" targetFramework="xamarinmac20" />
<package id="System.Text.RegularExpressions" version="4.1.0" targetFramework="xamarinmac20" />
<package id="System.Threading" version="4.0.11" targetFramework="xamarinmac20" />
<package id="System.Threading.Tasks" version="4.0.11" targetFramework="xamarinmac20" />
<package id="System.Xml.ReaderWriter" version="4.0.11" targetFramework="xamarinmac20" />
<package id="System.Xml.XDocument" version="4.0.11" targetFramework="xamarinmac20" />
</packages>
53 changes: 53 additions & 0 deletions src/SimpleAuth.Mac/AppleEventsHelper.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
//
// Copyright 2016 Clancey
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
using System;
using Foundation;

namespace Foundation
{
public static class AppleEventParameters
{
static uint FourCC (string s)
{
return (uint)(((int)s [0]) << 24 |
((int)s [1]) << 16 |
((int)s [2]) << 8 |
((int)s [3]));
}


public static uint DirectObject => FourCC (keyDirectObject);
public static uint ErrorNumber => FourCC (keyErrorNumber);
public static uint ErrorString => FourCC (keyErrorString);
public static uint ProcessSerialNumber => FourCC (keyProcessSerialNumber);
public static uint PreDispatch => FourCC (keyPreDispatch);
public static uint SelectProc => FourCC (keySelectProc);
public static uint AERecorderCount => FourCC (keyAERecorderCount);
public static uint AEVersion => FourCC (keyAEVersion);


/* Keywords for Apple event parameters */
const string keyDirectObject = "----";
const string keyErrorNumber = "errn";
const string keyErrorString = "errs";
const string keyProcessSerialNumber = "psn "; /* Keywords for special handlers */
const string keyPreDispatch = "phac"; /* preHandler accessor call */
const string keySelectProc = "selh"; /* more selector call */
/* Keyword for recording */
const string keyAERecorderCount = "recr"; /* available only in vers 1.0.1 and greater */
/* Keyword for version information */
const string keyAEVersion = "vers"; /* available only in vers 1.0.1 and greater */
}
}
117 changes: 117 additions & 0 deletions src/SimpleAuth.Mac/NativeSafariAuthenticator.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
//
// Copyright 2016 Clancey
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
using System;
using System.Collections.Generic;
using Foundation;
using System.Linq;
using System.Threading.Tasks;
using System.Web;
using AppKit;

namespace SimpleAuth
{
public class NativeSafariAuthenticator
{
public NativeSafariAuthenticator ()
{
}
const string CFBundleUrlError = "CFBundleURLSchemes are required for Native Safari Auth";
static Dictionary<string, WebAuthenticator> authenticators = new Dictionary<string, WebAuthenticator> ();
public static void Activate ()
{
if (!GetCFBundleURLSchemes ().Any ())
throw new Exception (CFBundleUrlError);

OAuthApi.ShowAuthenticator = ShowAuthenticator;
}
public static void ShowAuthenticator (WebAuthenticator authenticator)
{
var urls = GetCFBundleURLSchemes ();
if (!urls.Any ()) {
authenticator.OnError (CFBundleUrlError);
return;
}

//TODO: validate the proper url is in there

var invoker = new Foundation.NSObject ();
invoker.BeginInvokeOnMainThread (async () => await BeginAuthentication( authenticator));
}

static async Task BeginAuthentication (WebAuthenticator authenticator)
{
try {
var uri = (await authenticator.GetInitialUrl ());
string redirectUrl = uri.GetParameter ("redirect_uri");
var scheme = new Uri (redirectUrl).Scheme;
if (!VerifyHasUrlScheme(scheme)) {
authenticator.OnError ($"Unable to redirect {redirectUrl}, Please add the Url Scheme to the info.plist");
return;
}
var url = new NSUrl (uri.AbsoluteUri);
var opened = NSWorkspace.SharedWorkspace.OpenUrl (url);
if (!opened)
authenticator.OnError ("Error opening Safari");
else
authenticators [scheme] = authenticator;
} catch (Exception ex) {
authenticator.OnError (ex.Message);
}
}

static bool VerifyHasUrlScheme (string scheme)
{
var schemes = GetCFBundleURLSchemes ();
return schemes.Any (x => x == scheme);
}
static string [] GetCFBundleURLSchemes ()
{
NSObject nsobj;
if (!NSBundle.MainBundle.InfoDictionary.TryGetValue ((NSString)"CFBundleURLTypes", out nsobj))
return new string [0];
var d = (nsobj as NSArray)?.GetItem<NSDictionary> (0);
if (!d?.TryGetValue ((NSString)"CFBundleURLSchemes", out nsobj) ?? false)
return new string [0];
var a = nsobj as NSArray;
var urls = ConvertToIEnumerable<NSString> (a).Select (x => x.ToString ()).ToArray ();
return urls;
}

static IEnumerable<T> ConvertToIEnumerable<T> (NSArray array) where T : class, ObjCRuntime.INativeObject
{
for (nuint i = 0; i < array.Count; i++) {
yield return array.GetItem<T> (i);
}

}
public static bool ResumeAuth (string url)
{
try {
var uri = new Uri (url);
var redirect = uri.Scheme;
var auth = authenticators [redirect];
var s = auth.CheckUrl (uri, new System.Net.Cookie [0]);
if (s) {
authenticators.Remove (redirect);
}
return s;

} catch (Exception ex) {
Console.WriteLine (ex);
}
return false;
}
}
}
2 changes: 2 additions & 0 deletions src/SimpleAuth.Mac/SimpleAuth.Mac.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,8 @@
<ItemGroup>
<Compile Include="AuthStorage.cs" />
<Compile Include="WebAuthenticator.cs" />
<Compile Include="NativeSafariAuthenticator.cs" />
<Compile Include="AppleEventsHelper.cs" />
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
Expand Down
2 changes: 1 addition & 1 deletion src/SimpleAuth/Providers/Google.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ public class GoogleApi : OAuthApi
public GoogleApi(string identifier, string clientId, string clientSecret, HttpMessageHandler handler = null) : base(identifier, clientId, clientSecret, handler)
{
this.TokenUrl = "https://accounts.google.com/o/oauth2/token";
#if __IOS__
#if __UNIFIED__
this.CurrentShowAuthenticator = NativeSafariAuthenticator.ShowAuthenticator;
#endif
}
Expand Down

0 comments on commit da72af7

Please sign in to comment.