Xamarin iOS: Pass credentials over http - ios

I am trying to pass credentials over http on my xamarin iOS project but its not working.
public partial class WebView : UIViewController
{
protected override void ViewDidLoad()
{
webView.LoadRequest(new NSUrlRequest(new NSUrl("https:example.com")));
webView.AllowsBackForwardNavigationGestures = true;
webView.NavigationDelegate = new WebViewDelegate(this);
}
}
public class WebViewDelegate : WKNavigationDelegate, INSUrlConnectionDataDelegate
{
public override void DidReceiveAuthenticationChallenge(WKWebView webView, NSUrlAuthenticationChallenge challenge, Action<NSUrlSessionAuthChallengeDisposition, NSUrlCredential> completionHandler)
{
//base.DidReceiveAuthenticationChallenge(webView, challenge, completionHandler);
completionHandler(NSUrlSessionAuthChallengeDisposition.PerformDefaultHandling, new NSUrlCredential("username", "password", NSUrlCredentialPersistence.ForSession));
Console.WriteLine("We are authenticated");
return;
}
}
can anyone advise how to resolve this issue ?
Update:
DidReceiveAuthenticationChallenge is being called and is being called continuously in a loop. Instead of getting the expected page , I am getting a blank page and it just says "Authenticate"

From Apple's doc on PerformDefaultHandling:
Use the default handling for the challenge as though this delegate method were not implemented. The provided credential parameter is ignored.
Try UseCredential instead:
var crendential = new NSUrlCredential("user", "pass", NSUrlCredentialPersistence.ForSession);
completionHandler(NSUrlSessionAuthChallengeDisposition.UseCredential, crendential);

Related

Login with Xamarin.Auth in IOS Project is not working

I'm using Xamarin.Auth to login to google and facebook, It works fine with Android Project but seem like presenter is not working with IOS, it can't opon the browser for login.
Here is my code to call Presenter in viewmodel
var authenticator = new OAuth2Authenticator(
clientId,
constants.FacebookScope,
new Uri(constants.FacebookAuthorizeUrl),
new Uri(constants.FacebookAccessTokenUrl),
null,
true
);
authenticator.Completed += OnAuthCompleted;
authenticator.Error += OnAuthError;
AuthenticationState.Authenticator = authenticator;
var presenter = new Xamarin.Auth.Presenters.OAuthLoginPresenter();
presenter.Login(authenticator);
And Here is my AppDelegate in IOS project
public partial class AppDelegate : global::Xamarin.Forms.Platform.iOS.FormsApplicationDelegate
{
//
// This method is invoked when the application has loaded and is ready to run. In this
// method you should instantiate the window, load the UI into it and then make the window
// visible.
//
// You have 17 seconds to return from this method, or iOS will terminate your application.
//
public override bool FinishedLaunching(UIApplication app, NSDictionary options)
{
FFImageLoading.Forms.Platform.CachedImageRenderer.Init();
Rg.Plugins.Popup.Popup.Init();
global::Xamarin.Forms.Forms.Init();
global::Xamarin.Auth.Presenters.XamarinIOS.AuthenticationConfiguration.Init();
//global::Xamarin.Auth.WebViewConfiguration.IOS.UserAgent = "moljac++";
XamEffects.iOS.Effects.Init();
FFImageLoading.Forms.Platform.CachedImageRenderer.Init();
CachedImageRenderer.InitImageSourceHandler();
LoadApplication(new App());
return base.FinishedLaunching(app, options);
}
public override bool OpenUrl
(
UIApplication application,
NSUrl url,
string sourceApplication,
NSObject annotation
)
{
// Convert iOS NSUrl to C#/netxf/BCL System.Uri - common API
Uri uri_netfx = new Uri(url.AbsoluteString);
// load redirect_url Page (send it back to Xamarin.Auth)
// for Url parsing and raising Complete or Error events
AuthenticationState.Authenticator.OnPageLoading(uri_netfx);
return true;
}
}

ICloudStorage.GetChildren() never return

I'm trying to access Google Drive with CloudRail using the following codes.
// Actual string value removed.
private const string GDRIVE_CLIENT_ID = "client_id";
private const string ANDROID_PACKAGE_NAME = "package_name";
private const string CLOUDRAIL_APP_KEY = "app_key";
private readonly string REDIRECT_URL = $"{ANDROID_PACKAGE_NAME}:/oauth2redirect";
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
// Set CloudRail application key.
CloudRail.AppKey = CLOUDRAIL_APP_KEY;
// Set our view from the "main" layout resource
SetContentView(Resource.Layout.Main);
try
{
var googleDrive = new GoogleDrive(this, GDRIVE_CLIENT_ID, "", REDIRECT_URL, "state");
googleDrive.UseAdvancedAuthentication();
m_Service = googleDrive;
Action act = () =>
{
var list = m_Service.GetChildren(#"/");
// The function call never return.
};
var thread = new Thread(new ThreadStart(act));
thread.Start();
}
catch (Exception ex)
{
}
}
After calling into ICloudStorage.GetChildren(), my apps get redirected to login into Google account. After user has logged in to Google account and granted consent to the application, the function call never return. No exception is caught either.
What could have go wrong?
I got a reply from CloudRail support team and manage to solved the issue with their help.
You need to include the IntentFilter and LaunchMode to SingleTask on top of your activity.
Also you need to put OnNewIntent method as shown below:
[Activity(Label = "Awesome.Android", LaunchMode = Android.Content.PM.LaunchMode.SingleTask)]
[IntentFilter(new[] { Intent.ActionView }, Categories = new[] { Intent.CategoryBrowsable, Intent.CategoryDefault }, DataScheme = "Android_Package_Name")]
public class MainActivity : Activity
{
protected override void OnNewIntent(Intent intent)
{
CloudRail.AuthenticationResponse = intent;
base.OnNewIntent(Intent);
}
}
The key is that the corresponding Activity class (in my case, MainActivity) has to be decorated with IntentFilter. Also, OnNewItent has to be overridden and passing the response back to CloudRail.AuthenticationResponse in the override.
I also found that android package name must be in full lower case, otherwise it won't work either.
Edit [2018.07.19]
Android package name must contain at least one period character (.), otherwise, you may encounter invalid_request - missing authority error.

Xamarin IOS Facebook SDK LoginButton

Im new to Xamarin and IOS development and dont understand why I get this following error:
But first some Information:
Im using this SDK:
https://components.xamarin.com/view/facebookios
and creating my LoginButtin in my ViewController in ViewDidLoad like this:
loginButton = new LoginButton(new CGRect(48, 0, 218, 46))
{
LoginBehavior = LoginBehavior.Native,
ReadPermissions = readPermissions.ToArray()
};
View.AddSubview(button);
But in my Storyboard I get this error message:
Edit: my ViewController.cs
using System;
using System.Collections.Generic;
using UIKit;
namespace FacebookLogin
{
public partial class ViewController : UIViewController
{
List<string> readPermissions = new List<string> { "public_profile" };
LoginButton loginButton;
public ViewController(IntPtr handle) : base(handle)
{
}
public override void ViewDidLoad()
{
base.ViewDidLoad();
// Perform any additional setup after loading the view, typically from a nib.
loginButton = new LoginButton(new CGRect(48, 0, 218, 46))
{
LoginBehavior = LoginBehavior.Native,
ReadPermissions = readPermissions.ToArray()
};
View.AddSubview(button);
}
public override void DidReceiveMemoryWarning()
{
base.DidReceiveMemoryWarning();
// Release any cached data, images, etc that aren't in use.
}
}
}
Make sure to follow the instructions found on the getting started page. I see an empty component in your solution explorer but just in case, make sure that you installed Xamarin.Facebook.iOS 4.27.1 with nugget. Of course, you also need to set up your facebook app, login, and configure the iOS portion (like setting the BundleID).
Don't create the button in the controller. What you can do is use the storyBoard designer to drop in a regular button. Then, in the properties window click on Class and it should open a dropdown menu. In the selection you should see FBSDKLoginButton, select that class. Give it a name like btnFacebook.
In the codebehind for your controller it will look like this:
string[] readPermissions = { "public_profile" };
public override void ViewDidLoad()
{
base.ViewDidLoad();
btn.LoginBehavior = LoginBehavior.Native;
btnFacebook.ReadPermissions = readPermissions;
// Handle actions once the user is logged in
btnFacebook.Completed += LoginView_Completed;
// Handle actions once the user is logged out
btnFacebook.LoggedOut += LoginView_LoggedOut;
}
private void LoginView_Completed(object sender, LoginButtonCompletedEventArgs e)
{
if (e.Error != null)
{
return;
}
if (e.Result.IsCancelled)
{
return;
}
}
private void LoginView_LoggedOut(object sender, EventArgs e)
{
}
For good measure, clean solution and recompile. The login button won't appear as a facebook login button in your designer but on runtime it will.
As for your error, I don't see anything in your designer so it's curious that it's giving you an error like that. Open the Document Outline (View -> Other Windows -> Document Outline) and see if there's any invisible garbage (elements that aren't being rendered) that has to be deleted.
First Of All! You're on the right Way To solve your issue
and Secondly, I would Suggest you that you have created a controller in the above image you need to create a View Controller File and then add a Login Screen Like a Username named Textbox Then a Password named Textbox and A login Button and then View Controller will automatically created once you save the view And Then Finally, You Save the view Controller By Adding the Following Code
partial void login_TouchUpInside(UIButton sender)
{
var auth = new OAuth2Authenticator(clientId: "YOUR_CLIENT_ID", scope: "", authorizeUrl: new Uri("https://m.facebook.com/dialog/oauth/"), redirectUrl: new Uri("http://www.facebook.com/connect/login_success.html"));
auth.Completed += Auth_Completed;
var ui = auth.GetUI();
PresentViewController(ui, true, null);
}
private async void Auth_Completed(object sender, AuthenticatorCompletedEventArgs e)
{
if (e.IsAuthenticated)
{
var request = new OAuth2Request("POST", new Uri("YOUR Location Where You want to reach After Login"), null, e.Account);
//fb://profile/<id> For opening in Facebook App.
}
DismissViewController(true, null);
}
You See the Above Code And If you Want to Open the Facebook Link In Facebook Application Just Replace URL with
fb://profile/<id>

Can't call web api controller inside the signalr OnDisconnected method

I have an mvc web apllication with signalr and i want to update the table in the published web api.
calling web api controller to get users inside the Onconnected method works fine:
public override async Task OnConnected()
{
var users = await _client.GetAsync("chats/users");
Clients.All.userConnected();
}
But when i place the code inside the OnDisconnected method it gives me an error:
public override async Task OnDisconnected(bool stopCalled)
{
var users = await _client.GetAsync("chats/users");
}
Why is this happening? this is the whole Hub code:
private static IHubContext hubContext = GlobalHost.ConnectionManager.GetHubContext<ChatHub>();
private HttpClient _client;
public ChatHub()
{
AccessDelegatingHandler handler = new AccessDelegatingHandler();
_client = HttpClientFactory.Create(handler);
_client.BaseAddress = new Uri(ClsConfig.GetConfiguration().APIBaseAddress);
}
// Send new message to group chat.
public static void SendGroupMessage(MessageDetailModel messageDetail)
{
hubContext.Clients.All.newGroupMessageReceived(messageDetail);
}
public override async Task OnConnected()
{
var users = await _client.GetAsync("chats/users");
Clients.All.userConnected();
}
public override Task OnReconnected()
{
return base.OnReconnected();
}
public override async Task OnDisconnected(bool stopCalled)
{
var users = await _client.GetAsync("chats/users");
}
EDIT:
I found out that when i place var user = Context.User.Identity; inside the OnDisconnected method the user is IsAuthenticated = true but when i place a break point inside the AccessDelegatingHandler class the var identity = (ClaimsIdentity)HttpContext.Current.User.Identity; line gives an error and is IsAuthenticated = false
By the time the onDisconnected event fires, you are likely already disconnected, and there is no guarantee that your code will run, (its a known issue with Signalr) also are you monitoring the onDisconnected in the client or the server? It looks like you are trying to handle it from the server, and you should be handling it from the client.
This link should help to understand why this is the way it is.
https://learn.microsoft.com/en-us/aspnet/signalr/overview/guide-to-the-api/handling-connection-lifetime-events#clientdisconnect

Xamarin way to open self signed certificate webpage in UIWebView

As the question title described, I want to open a self signed webpage within an UIWebview (Xamarin.iOS)
By default, self signed webpages do not load in an UIWebView.
Important requirements for the solution:
It should be accepted by Apple when I want to submit the app to the Apple app store (so a custom NSUrlRequest does not fit).
It should load css and javascript properly.
I found a possible solution on stackoverflow but this is for native iOS.
https://stackoverflow.com/a/11664147
I was also wondering if the solution described above requires to login using a NSUrlConnectionDelegate.
The desired solution should be that the user can fill-in the credentials by himself using the UIWebView.
Could someone provide the Xamarin solution for this? I tried it by myself but couldn't get it work.
Thanks in advance for your help.
I know this is quite an old post, but it was quite an interesting question, so I had to take a go at at. So if you still need it (most likely not) or if anyone finds this post, here are a ported version of the native UIWebView with support for self signed. It can be used as a regular UIWebView with the exception that it takes a hostname as additional parameter, which should be the hostname of the page where certificate check should be disabled.
public class InsecureWebView : UIWebView, INSUrlConnectionDataDelegate, IUIWebViewDelegate
{
public InsecureWebView(string baseUrl) : base()
{
Setup (baseUrl);
}
public InsecureWebView(CoreGraphics.CGRect rect, string baseUrl) : base(rect)
{
Setup (baseUrl);
}
public InsecureWebView(NSCoder coder, string baseUrl) : base(coder)
{
Setup (baseUrl);
}
public InsecureWebView(NSObjectFlag t, string baseUrl) : base(t)
{
Setup (baseUrl);
}
public InsecureWebView(IntPtr handler, string baseUrl) : base(handler)
{
Setup (baseUrl);
}
string baseUrl = null;
bool authenticated;
NSUrlRequest failedRequest;
private void Setup(string baseUrl)
{
this.Delegate = this;
this.baseUrl = baseUrl;
}
[Foundation.Export ("webView:shouldStartLoadWithRequest:navigationType:")]
public bool ShouldStartLoad (UIKit.UIWebView webView, Foundation.NSUrlRequest request, UIKit.UIWebViewNavigationType navigationType)
{
var result = authenticated;
if (!authenticated) {
failedRequest = request;
NSUrlConnection.FromRequest (request, this);
}
return result;
}
[Foundation.Export ("connection:willSendRequestForAuthenticationChallenge:")]
public void WillSendRequestForAuthenticationChallenge (NSUrlConnection connection, NSUrlAuthenticationChallenge challenge)
{
if (challenge.ProtectionSpace.AuthenticationMethod == NSUrlProtectionSpace.AuthenticationMethodServerTrust) {
var baseUrl = new NSUrl (this.baseUrl);
if (challenge.ProtectionSpace.Host == baseUrl.Host) {
challenge.Sender.UseCredential (NSUrlCredential.FromTrust (challenge.ProtectionSpace.ServerSecTrust), challenge);
}
}
challenge.Sender.ContinueWithoutCredential (challenge);
}
[Foundation.Export ("connection:didReceiveResponse:")]
public void DidReceivedResponse(NSUrlConnection connection, NSUrlResponse response)
{
authenticated = true;
connection.Cancel ();
LoadRequest (failedRequest);
}
}

Resources