diff --git a/src/XamarinAzureChallenge.sln b/src/XamarinAzureChallenge.sln old mode 100755 new mode 100644 index 1e66397..65986ca --- a/src/XamarinAzureChallenge.sln +++ b/src/XamarinAzureChallenge.sln @@ -7,7 +7,7 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "XamarinAzureChallenge.Andro EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "XamarinAzureChallenge.iOS", "XamarinAzureChallenge\XamarinAzureChallenge.iOS\XamarinAzureChallenge.iOS.csproj", "{2C81F630-FC66-4BEC-A800-56A0C743F3D3}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "XamarinAzureChallenge", "XamarinAzureChallenge\XamarinAzureChallenge\XamarinAzureChallenge.csproj", "{906E148B-01D5-4106-9C5B-404A8B655069}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "XamarinAzureChallenge", "XamarinAzureChallenge\XamarinAzureChallenge\XamarinAzureChallenge.csproj", "{906E148B-01D5-4106-9C5B-404A8B655069}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "XamarinAzureChallenge.Functions", "XamarinAzureChallenge\XamarinAzureChallenge.Functions\XamarinAzureChallenge.Functions.csproj", "{2A44CE99-0A65-4AE7-897F-D2EA679A42B7}" EndProject diff --git a/src/XamarinAzureChallenge/XamarinAzureChallenge.Android/MainActivity.cs b/src/XamarinAzureChallenge/XamarinAzureChallenge.Android/MainActivity.cs old mode 100755 new mode 100644 index 5814cc0..68359f7 --- a/src/XamarinAzureChallenge/XamarinAzureChallenge.Android/MainActivity.cs +++ b/src/XamarinAzureChallenge/XamarinAzureChallenge.Android/MainActivity.cs @@ -1,11 +1,15 @@ -using Android.App; +using System; +using Android.App; +using Android.Content; using Android.Content.PM; using Android.OS; using Android.Runtime; +using XamarinAzureChallenge.Pages; namespace XamarinAzureChallenge.Droid { - [Activity(Label = "XamarinAzureChallenge", Icon = "@mipmap/icon", Theme = "@style/MainTheme", MainLauncher = true, ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation)] + [Activity(Label = "XamarinAzureChallenge", Icon = "@mipmap/icon", Theme = "@style/MainTheme", MainLauncher = true, ScreenOrientation = ScreenOrientation.Portrait)] + [IntentFilter(new string[] { Intent.ActionView }, Categories = new[] { Intent.CategoryDefault, Intent.CategoryBrowsable }, DataSchemes = new[] { "xamarinazurechallenge" })] public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity { public override void OnRequestPermissionsResult(int requestCode, string[] permissions, [GeneratedEnum] Permission[] grantResults) @@ -25,6 +29,29 @@ namespace XamarinAzureChallenge.Droid global::Xamarin.Forms.Forms.Init(this, savedInstanceState); LoadApplication(new App()); + + if (Intent?.Data is Android.Net.Uri callbackUri) + ExecuteCallbackUri(callbackUri); + } + + async void ExecuteCallbackUri(Android.Net.Uri callbackUri) + { + if (Xamarin.Forms.Application.Current.MainPage is Xamarin.Forms.NavigationPage navigationPage) + { + navigationPage.Pushed += HandlePushed; + + await navigationPage.PushAsync(new UserDataPage()); + + async void HandlePushed(object sender, Xamarin.Forms.NavigationEventArgs e) + { + if (e.Page is UserDataPage) + { + navigationPage.Pushed -= HandlePushed; + + await AzureAuthenticationService.AuthorizeSession(new Uri(callbackUri.ToString())); + } + } + } } } } \ No newline at end of file diff --git a/src/XamarinAzureChallenge/XamarinAzureChallenge.Android/Properties/AndroidManifest.xml b/src/XamarinAzureChallenge/XamarinAzureChallenge.Android/Properties/AndroidManifest.xml index e00c35f..6071e70 100644 --- a/src/XamarinAzureChallenge/XamarinAzureChallenge.Android/Properties/AndroidManifest.xml +++ b/src/XamarinAzureChallenge/XamarinAzureChallenge.Android/Properties/AndroidManifest.xml @@ -1,5 +1,5 @@  - + diff --git a/src/XamarinAzureChallenge/XamarinAzureChallenge.Android/XamarinAzureChallenge.Android.csproj b/src/XamarinAzureChallenge/XamarinAzureChallenge.Android/XamarinAzureChallenge.Android.csproj index 6e629e1..6faae6b 100644 --- a/src/XamarinAzureChallenge/XamarinAzureChallenge.Android/XamarinAzureChallenge.Android.csproj +++ b/src/XamarinAzureChallenge/XamarinAzureChallenge.Android/XamarinAzureChallenge.Android.csproj @@ -17,6 +17,7 @@ Assets v9.0 Xamarin.Android.Net.AndroidClientHandler + True @@ -33,7 +34,7 @@ true - pdbonly + none true bin\Release prompt diff --git a/src/XamarinAzureChallenge/XamarinAzureChallenge.Functions/Functions/SubmitChallengeFunction.cs b/src/XamarinAzureChallenge/XamarinAzureChallenge.Functions/Functions/SubmitChallengeFunction.cs index d6d4f09..5e89a88 100644 --- a/src/XamarinAzureChallenge/XamarinAzureChallenge.Functions/Functions/SubmitChallengeFunction.cs +++ b/src/XamarinAzureChallenge/XamarinAzureChallenge.Functions/Functions/SubmitChallengeFunction.cs @@ -23,7 +23,7 @@ namespace Microsoft.XamarinAzureChallenge.AZF private static HttpClient Client => clientHolder.Value; [FunctionName(nameof(SubmitChallengeFunction))] - public static async Task Run([HttpTrigger(AuthorizationLevel.Function, "post")][FromBody] User user, ILogger log, ExecutionContext context) + public static async Task Run([HttpTrigger(AuthorizationLevel.Function, "post", Route = nameof(SubmitChallengeFunction) + "/{azureSubscriptionId}")][FromBody] User user, ILogger log, ExecutionContext context, string azureSubscriptionId) { log.LogInformation("HTTP Triggered"); diff --git a/src/XamarinAzureChallenge/XamarinAzureChallenge.Shared/Models/AzureAuthenticationCompletedEventArgs.cs b/src/XamarinAzureChallenge/XamarinAzureChallenge.Shared/Models/AzureAuthenticationCompletedEventArgs.cs new file mode 100644 index 0000000..0fb2e47 --- /dev/null +++ b/src/XamarinAzureChallenge/XamarinAzureChallenge.Shared/Models/AzureAuthenticationCompletedEventArgs.cs @@ -0,0 +1,11 @@ +using System; +namespace XamarinAzureChallenge.Shared +{ + public class AzureAuthenticationCompletedEventArgs : EventArgs + { + public AzureAuthenticationCompletedEventArgs(bool isAuthenticationSuccessful) => + IsAuthenticationSuccessful = isAuthenticationSuccessful; + + public bool IsAuthenticationSuccessful { get; } + } +} diff --git a/src/XamarinAzureChallenge/XamarinAzureChallenge.Shared/Models/AzureClientIdModel.cs b/src/XamarinAzureChallenge/XamarinAzureChallenge.Shared/Models/AzureClientIdModel.cs new file mode 100644 index 0000000..37549fb --- /dev/null +++ b/src/XamarinAzureChallenge/XamarinAzureChallenge.Shared/Models/AzureClientIdModel.cs @@ -0,0 +1,7 @@ +namespace XamarinAzureChallenge.ViewModels +{ + public class AzureClientIdModel + { + public string ClientId { get; set; } + } +} \ No newline at end of file diff --git a/src/XamarinAzureChallenge/XamarinAzureChallenge.Shared/Models/AzureToken.cs b/src/XamarinAzureChallenge/XamarinAzureChallenge.Shared/Models/AzureToken.cs new file mode 100644 index 0000000..68fa6e8 --- /dev/null +++ b/src/XamarinAzureChallenge/XamarinAzureChallenge.Shared/Models/AzureToken.cs @@ -0,0 +1,32 @@ +using System; +using Newtonsoft.Json; + +namespace XamarinAzureChallenge.Shared +{ + public class AzureToken + { + [JsonProperty("access_token")] + public string AccessToken { get; set; } + + [JsonProperty("token_type")] + public string TokenType { get; set; } + + [JsonProperty("expires_in")] + public long ExpiresIn { get; set; } + + [JsonProperty("expires_on")] + public long ExpiresOn { get; set; } + + [JsonProperty("resource")] + public Uri Resource { get; set; } + + [JsonProperty("refresh_token")] + public string RefreshToken { get; set; } + + [JsonProperty("scope")] + public string Scope { get; set; } + + [JsonProperty("id_token")] + public string IdToken { get; set; } + } +} diff --git a/src/XamarinAzureChallenge/XamarinAzureChallenge.Shared/XamarinAzureChallenge.Shared.projitems b/src/XamarinAzureChallenge/XamarinAzureChallenge.Shared/XamarinAzureChallenge.Shared.projitems old mode 100755 new mode 100644 index 75b86b1..e3f55b1 --- a/src/XamarinAzureChallenge/XamarinAzureChallenge.Shared/XamarinAzureChallenge.Shared.projitems +++ b/src/XamarinAzureChallenge/XamarinAzureChallenge.Shared/XamarinAzureChallenge.Shared.projitems @@ -10,6 +10,9 @@ + + + diff --git a/src/XamarinAzureChallenge/XamarinAzureChallenge.iOS/AppDelegate.cs b/src/XamarinAzureChallenge/XamarinAzureChallenge.iOS/AppDelegate.cs old mode 100755 new mode 100644 index 46cc0c2..054cb9b --- a/src/XamarinAzureChallenge/XamarinAzureChallenge.iOS/AppDelegate.cs +++ b/src/XamarinAzureChallenge/XamarinAzureChallenge.iOS/AppDelegate.cs @@ -1,5 +1,10 @@ -using Foundation; +using System; +using System.Threading.Tasks; +using Foundation; +using SafariServices; using UIKit; +using Xamarin.Forms; +using XamarinAzureChallenge.ViewModels; namespace XamarinAzureChallenge.iOS { @@ -13,5 +18,53 @@ namespace XamarinAzureChallenge.iOS return base.FinishedLaunching(uiApplication, launchOptions); } + + public override bool OpenUrl(UIApplication app, NSUrl url, NSDictionary options) + { + var callbackUri = new Uri(url.AbsoluteString); + + HandleCallbackUri(callbackUri); + + return true; + } + + async void HandleCallbackUri(Uri callbackUri) + { + await CloseSFSafariViewController(); + await AzureAuthenticationService.AuthorizeSession(callbackUri); + } + + async Task CloseSFSafariViewController() + { + while (await GetVisibleViewController() is SFSafariViewController sfSafariViewController) + { + await Device.InvokeOnMainThreadAsync(async () => + { + await sfSafariViewController.DismissViewControllerAsync(true); + sfSafariViewController.Dispose(); + sfSafariViewController = null; + }); + } + } + + Task GetVisibleViewController() + { + return Device.InvokeOnMainThreadAsync(() => + { + var rootController = UIApplication.SharedApplication.KeyWindow.RootViewController; + + switch (rootController.PresentedViewController) + { + case UINavigationController navigationController: + return navigationController.TopViewController; + case UITabBarController tabBarController: + return tabBarController.SelectedViewController; + case null: + return rootController; + default: + return rootController.PresentedViewController; + } + }); + } } } diff --git a/src/XamarinAzureChallenge/XamarinAzureChallenge.iOS/Info.plist b/src/XamarinAzureChallenge/XamarinAzureChallenge.iOS/Info.plist index ed198d5..552392a 100755 --- a/src/XamarinAzureChallenge/XamarinAzureChallenge.iOS/Info.plist +++ b/src/XamarinAzureChallenge/XamarinAzureChallenge.iOS/Info.plist @@ -2,41 +2,50 @@ - UIDeviceFamily - - 1 - 2 - - UISupportedInterfaceOrientations - - UIInterfaceOrientationPortrait - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - UISupportedInterfaceOrientations~ipad - - UIInterfaceOrientationPortrait - UIInterfaceOrientationPortraitUpsideDown - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - MinimumOSVersion - 8.0 - CFBundleDisplayName - XamarinAzureChallenge - CFBundleIdentifier - com.companyname.XamarinAzureChallenge - CFBundleVersion - 1.0 - UILaunchStoryboardName - LaunchScreen - CFBundleName - XamarinAzureChallenge - XSAppIconAssets - Assets.xcassets/AppIcon.appiconset - UIAppFonts - - roboto.regular.ttf - + UIDeviceFamily + + 1 + 2 + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + MinimumOSVersion + 11.0 + CFBundleDisplayName + XamarinAzureChallenge + CFBundleIdentifier + com.xamarin.XamarinAzureChallenge + CFBundleVersion + 1.0 + UILaunchStoryboardName + LaunchScreen + CFBundleName + XamarinAzureChallenge + XSAppIconAssets + Assets.xcassets/AppIcon.appiconset + UIAppFonts + + roboto.regular.ttf + + CFBundleURLTypes + + + CFBundleURLName + com.xamarin.XamarinAzureChallenge + CFBundleURLSchemes + + xamarinazurechallenge + + + diff --git a/src/XamarinAzureChallenge/XamarinAzureChallenge.iOS/XamarinAzureChallenge.iOS.csproj b/src/XamarinAzureChallenge/XamarinAzureChallenge.iOS/XamarinAzureChallenge.iOS.csproj index 7dd16bb..3e025ba 100644 --- a/src/XamarinAzureChallenge/XamarinAzureChallenge.iOS/XamarinAzureChallenge.iOS.csproj +++ b/src/XamarinAzureChallenge/XamarinAzureChallenge.iOS/XamarinAzureChallenge.iOS.csproj @@ -13,12 +13,13 @@ Resources XamarinAzureChallenge.iOS NSUrlSessionHandler + True true - full + portable false bin\iPhoneSimulator\Debug DEBUG @@ -43,7 +44,7 @@ true - full + portable false bin\iPhone\Debug DEBUG diff --git a/src/XamarinAzureChallenge/XamarinAzureChallenge/Pages/ResultPage.xaml.cs b/src/XamarinAzureChallenge/XamarinAzureChallenge/Pages/ResultPage.xaml.cs old mode 100755 new mode 100644 index 579afca..421aa03 --- a/src/XamarinAzureChallenge/XamarinAzureChallenge/Pages/ResultPage.xaml.cs +++ b/src/XamarinAzureChallenge/XamarinAzureChallenge/Pages/ResultPage.xaml.cs @@ -4,7 +4,7 @@ using XamarinAzureChallenge.ViewModels; namespace XamarinAzureChallenge.Pages { public partial class ResultPage : BaseContentPage - { + { public ResultPage(HttpStatusCode statusCode) { InitializeComponent(); diff --git a/src/XamarinAzureChallenge/XamarinAzureChallenge/Pages/UserDataPage.xaml b/src/XamarinAzureChallenge/XamarinAzureChallenge/Pages/UserDataPage.xaml index f99b22b..d249f55 100644 --- a/src/XamarinAzureChallenge/XamarinAzureChallenge/Pages/UserDataPage.xaml +++ b/src/XamarinAzureChallenge/XamarinAzureChallenge/Pages/UserDataPage.xaml @@ -50,7 +50,7 @@ + Value="Black" /> @@ -64,6 +64,8 @@ Value="Black" /> +