ADAL invalid redirect uri - xamarin

Note: i'm using an experimental pre-release of microsoft's latest adal
I'm trying to get my identity providers to work on the mobile applications. So far I've been able to load my identity providers and managed to get the login page to show (except for facebook).
The problem is that whenever i actually try to login i'm getting some error in the form off "invalid redirect uri".
Google, for instance, will say: "The redirect URI in the request: https://login.microsoftonline.com/... did not match a registered redirect URI.
Facebook will show: "Given URL is not allowed by the application configuration: One or more of the given URLs is not allowed by the App's settings. It must match the website URL or Canvas URL, or the domain must be a subdomain of one of the App's domains."
As far as I understand you don't actually need to register the mobile application anymore with the different identity providers because Azure sits in between you and them. Azure handles the connection, gets your token and uses it to identify you. It should then return a set of "azure tokens" to you.
To my knowledge the used redirect URI is registered on the portal since I'm able to load the identity providers in the first place?
Not to mention it seems to be a default URL that's used by many applications: urn:ietf:wg:oauth:2.0:oob which simply tells it to return it to some none-browser based application?
This is the code i'm using to actually do the login/signup:
private static String AUTHORITY_URL = "https://login.microsoftonline.com/<directory>/oauth2/authorize/";
private static String CLIENT_ID = "my_client_id";
private static String[] SCOPES = { "my_client_id" };
private static String[] ADDITIONAL_SCOPES = { "" };
private static String REDIRECT_URL = "urn:ietf:wg:oauth:2.0:oob";
private static String CORRELATION_ID = "";
private static String USER_HINT = "";
private static String EXTRA_QP = "nux=1";
private static String FB_POLICY = "B2C_1_<your policy>";
private static String EMAIL_SIGNIN_POLICY = "B2C_1_SignIn";
private static String EMAIL_SIGNUP_POLICY = "B2C_1_SignUp";
public async Task<AuthenticationResult> Login(IPlatformParameters parameters, bool isSignIn)
{
var authContext = new AuthenticationContext(AUTHORITY_URL, new TokenCache());
if (CORRELATION_ID != null &&
CORRELATION_ID.Trim().Length != 0)
{
authContext.CorrelationId = Guid.Parse(CORRELATION_ID);
}
String policy = "";
if (isSignIn)
policy = EMAIL_SIGNIN_POLICY;
else
policy = EMAIL_SIGNUP_POLICY;
return await authContext.AcquireTokenAsync(SCOPES, ADDITIONAL_SCOPES, CLIENT_ID, new Uri(REDIRECT_URL), parameters, UserIdentifier.AnyUser, EXTRA_QP, policy);
}
microsoft's documentation isn't really helping because most are either empty (they're literally not yet typed out) or it's some help topic from over a year ago. This stuff is pretty new so documentation seems to be hard to come by.
So, dear people of stackoverflow, what am I missing? Why is it saying that the redirect urI is invalid when it's been registered on the azure web portal? And if the redirect URI is invalid why can I retrieve the identity providers in the first place?

why is it that i can't seem to find solutions after hours of searching, yet when i post a question here i somehow find the answer within minutes...
It was quite a stupid mistake at that, one of my collegues had sent me the wrong authority url.
The funny thing is that it was correct "enough" to load the identity providers we had installed on the portal but not correct enough to handle actually signing in or up.
I initially used:
https://login.microsoftonline.com/<tenant_id>/oauth2/authorize/
where it should have been:
https://login.microsoftonline.com/<tenant_id>/oauth2/v2.0/authorize
You see that little "v2.0"? yeah that little bastard is what caused all the pain...

Related

AuthorizeAttribute does not work on ApiController inside Area

A few days ago, half of our Azure hosted ASP.NET Web API (.NET Framework) started playing up. It's been running fine for a number of months, then all of a sudden, customers couldn't log into one of our front end sites.
We have three applications that connect to the Web API. Two of them connect through the controllers in the top level Controllers folder, and one of them connects through the controllers inside an Area. It's this Area that is causing us pain.
public class MyAppAreaRegistration : AreaRegistration
{
public override string AreaName => "MyApp";
public override void RegisterArea(AreaRegistrationContext context)
{
context.MapRoute("MyAppApi", "myapp/api/{controller}/{action}");
}
}
Both parts of the Web API use the same code to generate Jwt Security Tokens, and unauthorized methods in both areas are okay.
private JwtSecurityToken GenerateSecurityToken(int userId, string username, int customerId)
{
var signingKey = GetSigningKey();
var audience = GetSiteUrl(); // Must match the url of the site
var issuer = GetSiteUrl(); // Must match the url of the site
var lifeTime = TimeSpan.FromHours(24);
var now = DateTime.Now;
var expiry = now.Add(lifeTime);
var claims = new[]
{
new Claim(JwtRegisteredClaimNames.Sub, userId.ToString()),
new Claim(JwtRegisteredClaimNames.UniqueName, username),
new Claim(JwtRegisteredClaimNames.Prn, customerId.ToString()),
new Claim(JwtRegisteredClaimNames.Iat, now.Ticks.ToString()),
new Claim(JwtRegisteredClaimNames.Exp, expiry.Ticks.ToString())
};
var token = AppServiceLoginHandler.CreateToken(claims, signingKey, audience, issuer, lifeTime);
return token;
}
After much effort trying to work out what could have changed, we implemented a CustomAuthorizeAttribute and applied it to a controller inside the Area and a controller outside the Area. The one outside the Area appears to have the actionContext.ControllerContext.RequestContext.Principal.Identity set correctly, but the one inside the area is empty. Not null. Just empty. We logged both the actionContext.ControllerContext.RequestContext.Principal as well as the Thread.CurrentPrincipal, but both are empty.
I can't seem to work out what is responsible for managing this data, and why it now refuses to do it for controllers with the area.
I'm able to access the token and extract the claims successfully.
All help will be appreciated.
Cheers

Google Search Appliance - GSA - configuration issue

I want to use GSAClient to access our company google search appliance project and retrieve searching result, but I don't get the configuration working at all.
The web UI is: http://kb.juniper.net
So in order to make GSAClientDemo working, how should I set:
HOSTNAME
SETTING_FRONTEND
Do I have to ask GSA admin for the settings?
// target GSA's hostname
private static final String HOSTNAME = "kb.juniper.net";
// query string to search for
private static final String QUERY_STRING = "juno";
// The value for the frontend configured for the GSA
// (If you dont know this, ask GSA admin for correct value for your target GSA.)
private static final String SETTING_FRONTEND = "InfoCenter";
public static void main(String[] args) throws IOException {
GSAClient client = new GSAClient(HOSTNAME);
GSAQuery query = new GSAQuery();
// typical way to generate query term.
GSAQueryTerm term = new GSAQueryTerm(QUERY_STRING);
query.setQueryTerm(term);
System.out.println("Searching for: "+query.getQueryString());
Hostname is the GSA domain name or ip
Frontend is not required
Complete example is here:
http://gsa-japi.sourceforge.net/onemin-tut.html
Do I have to ask GSA admin for the settings?
Yes. You need to check with your GSA admin for the HOST and front_end information. Only they can tell you. Unless, you know how to use GSA and are permitted to get the information for yourself.

Clickonce Autodetect Proxy

I have created a C sharp Wpf ClickOnce application which uses xml rpc for communincation. A lot of my users get there proxy settings in different ways. Some use a pac file, other from IE or dhcp etc. I want to automate this whole process of getting the proxy details in any kind of environment. I have tried a LOT of different code snippets but want to hear if something like this already exists.
I see the Xml Rpc documentation has a setProxy method but I'm not sure how to specify the username or passsword if one is used. This whole process is still a little bit confusing for me.
I have also tried many different pieces of code including the WebProxy Class and using DefaultCredentials,DefaultProxy,GetSystemWebProxy etc.
At the moment I'm going to try a dllimport using winhttp to get the proxy settings. I am not sure if one can do this in a Clickonce Deployment. Is the dllimport the same as p/invoke ?
As you can see I would appreciate some advice on how to go about getting ANY type of proxy setting.
Appreciate any feedback.
ClickOnce installation/update doesn't really support proxy authentication. It will use the information in IE, and sometimes the machine.config file. The definitive thread with all known information about this is here.
I haven't had have problems with proxy authentication from the standpoint of installing applications. When using our application, which called backend WCF services, we let the user provide his proxy authentication information, and we applied the settings programmatically when making the service calls. This has nothing to do with ClickOnce.
This worked for me :
public static IExample ProxyAndCredentials { get; set; }
public static string ProxyUrl { get; set; }
public static void SetupProxyAndCredentials() {
//Insert your website here where XmlRpc calls should go
var url = new Uri("http://www.example.com/");
try
{
ProxyUrl = WebRequest.DefaultWebProxy.GetProxy(url).ToString();
Log.Debug(url + " is using proxy " + ProxyUrl);
if (ProxyUrl == url.ToString() || ProxyUrl == url + "/"){
// A proxy is not in use here
ProxyUrl = "";
Log.Debug("No proxy is used for " + url);
}
else if (!String.IsNullOrEmpty(ProxyUrl)){
// A proxy is in use
ProxyAndCredentials.Proxy = new WebProxy(ProxyUrl);
Log.Debug("A proxy is used for " + url);
}
//Set credentials, in my experience it is better to always set these
ProxyAndCredentials.Credentials = CredentialCache.DefaultNetworkCredentials;
ProxyAndCredentials.Proxy.Credentials = CredentialCache.DefaultNetworkCredentials;
}
catch (Exception p)
{
//Handle Exception
}
}

Google+ insert moment using google-api-dotnet-client

I am trying to write an activity in Google+ using the dotnet-client. The issue is that I can't seem to get the configuration of my client app correctly. According to the Google+ Sign-In configuration and this SO question we need to add the requestvisibleactions parameter. I did that but it did not work. I am using the scope https://www.googleapis.com/auth/plus.login and I even added the scope https://www.googleapis.com/auth/plus.moments.write but the insert still did not work.
This is what my request url looks like:
https://accounts.google.com/ServiceLogin?service=lso&passive=1209600&continue=https://accounts.google.com/o/oauth2/auth?scope%3Dhttps://www.googleapis.com/auth/plus.login%2Bhttps://www.googleapis.com/auth/plus.moments.write%26response_type%3Dcode%26redirect_uri%3Dhttp://localhost/%26state%3D%26requestvisibleactions%3Dhttp://schemas.google.com/AddActivity%26client_id%3D000.apps.googleusercontent.com%26request_visible_actions%3Dhttp://schemas.google.com/AddActivity%26hl%3Den%26from_login%3D1%26as%3D-1fbe06f1c6120f4d&ltmpl=popup&shdf=Cm4LEhF0aGlyZFBhcnR5TG9nb1VybBoADAsSFXRoaXJkUGFydHlEaXNwbGF5TmFtZRoHQ2hpa3V0bwwLEgZkb21haW4aB0NoaWt1dG8MCxIVdGhpcmRQYXJ0eURpc3BsYXlUeXBlGgdERUZBVUxUDBIDbHNvIhTeWybcoJ9pXSeN2t-k8A4SUbfhsygBMhQivAmfNSs_LkjXXZ7bPxilXgjMsQ&scc=1
As you can see from there that there is a request_visible_actions and I even added one that has no underscore in case I got the parameter wrong (requestvisibleactions).
Let me say that my app is being authenticated successfully by the API. I can get the user's profile after being authenticated and it is on the "insert moment" part that my app fails. My insert code:
var body = new Moment();
var target = new ItemScope();
target.Id = referenceId;
target.Image = image;
target.Type = "http://schemas.google.com/AddActivity";
target.Description = description;
target.Name = caption;
body.Target = target;
body.Type = "http://schemas.google.com/AddActivity";
var insert =
new MomentsResource.InsertRequest(
// this is a valid service instance as I am using this to query the user's profile
_plusService,
body,
id,
MomentsResource.Collection.Vault);
Moment result = null;
try
{
result = insert.Fetch();
}
catch (ThreadAbortException)
{
// User was not yet authenticated and is being forwarded to the authorization page.
throw;
}
catch (Google.GoogleApiRequestException requestEx)
{
// here I get a 401 Unauthorized error
}
catch (Exception ex)
{
} `
For the OAuth flow, there are two issues with your request:
request_visible_actions is what is passed to the OAuth v2 server (don't pass requestvisibleactions)
plus.moments.write is a deprecated scope, you only need to pass in plus.login
Make sure your project references the latest version of the Google+ .NET client library from here:
https://developers.google.com/resources/api-libraries/download/stable/plus/v1/csharp
I have created a project on GitHub showing a full server-side flow here:
https://github.com/gguuss/gplus_csharp_ssflow
As Brettj said, you should be using the Google+ Sign-in Button as demonstrated in the latest Google+ samples from here:
https://github.com/googleplus/gplus-quickstart-csharp
First, ensure you are requesting all of the activity types you're writing. You will know this is working because the authorization dialog will show "Make your app activity available via Google, visible to you and: [...]" below the text that starts with "This app would like to". I know you checked this but I'm 90% sure this is why you are getting the 401 error code. The following markup shows how to render the Google+ Sign-In button requesting access to Add activities.
<div id="gConnect">
<button class="g-signin"
data-scope="https://www.googleapis.com/auth/plus.login"
data-requestvisibleactions="http://schemas.google.com/AddActivity"
data-clientId="YOUR_CLIENT_ID"
data-accesstype="offline"
data-callback="onSignInCallback"
data-theme="dark"
data-cookiepolicy="single_host_origin">
</button>
Assuming you have a PlusService object with the correct activity type set in data-requestvisibleactions, the following code, which you should be able to copy/paste to see it work, concisely demonstrates writing moments using the .NET client and has been tested to work:
Moment body = new Moment();
ItemScope target = new ItemScope();
target.Id = "replacewithuniqueforaddtarget";
target.Image = "http://www.google.com/s2/static/images/GoogleyEyes.png";
target.Type = "";
target.Description = "The description for the activity";
target.Name = "An example of add activity";
body.Target = target;
body.Type = "http://schemas.google.com/AddActivity";
MomentsResource.InsertRequest insert =
new MomentsResource.InsertRequest(
_plusService,
body,
"me",
MomentsResource.Collection.Vault);
Moment wrote = insert.Fetch();
Note, I'm including Google.Apis.Plus.v1.Data for convenience.
Ah it's that simple! Maybe not? I am answering my own question and consequently accept it as the answer (after a few days of course) so others having the same issue may be guided. But I will definitely up-vote Gus' answer for it led me to the fix for my code.
So according to #class answer written above and as explained on his blog the key to successfully creating a moment is adding the request_visible_actions parameter. I did that but my request still failed and it is because I was missing an important thing. You need to add one more parameter and that is the access_type and it should be set to offline. The OAuth request, at a minimum, should look like: https://accounts.google.com/o/oauth2/auth?scope=https://www.googleapis.com/auth/plus.login&response_type=code&redirect_uri=http://localhost/&request_visible_actions=http://schemas.google.com/AddActivity&access_type=offline.
For the complete and correct client code you can get Gus' example here or download the entire dotnet client library including the source and sample and add what I added below. The most important thing that you should remember is modifying your AuthorizationServerDescription for the Google API. Here's my version of the authenticator:
public static OAuth2Authenticator<WebServerClient> CreateAuthenticator(
string clientId, string clientSecret)
{
if (string.IsNullOrWhiteSpace(clientId))
throw new ArgumentException("clientId cannot be empty");
if (string.IsNullOrWhiteSpace(clientSecret))
throw new ArgumentException("clientSecret cannot be empty");
var description = GoogleAuthenticationServer.Description;
var uri = description.AuthorizationEndpoint.AbsoluteUri;
// This is the one that has been documented on Gus' blog site
// and over at Google's (https://developers.google.com/+/web/signin/)
// This is not in the dotnetclient sample by the way
// and you need to understand how OAuth and DNOA works.
// I had this already, see my original post,
// I thought it will make my day.
if (uri.IndexOf("request_visible_actions") < 1)
{
var param = (uri.IndexOf('?') > 0) ? "&" : "?";
description.AuthorizationEndpoint = new Uri(
uri + param +
"request_visible_actions=http://schemas.google.com/AddActivity");
}
// This is what I have been missing!
// They forgot to tell us about this or did I just miss this somewhere?
uri = description.AuthorizationEndpoint.AbsoluteUri;
if (uri.IndexOf("offline") < 1)
{
var param = (uri.IndexOf('?') > 0) ? "&" : "?";
description.AuthorizationEndpoint =
new Uri(uri + param + "access_type=offline");
}
// Register the authenticator.
var provider = new WebServerClient(description)
{
ClientIdentifier = clientId,
ClientSecret = clientSecret,
};
var authenticator =
new OAuth2Authenticator<WebServerClient>(provider, GetAuthorization)
{ NoCaching = true };
return authenticator;
}
Without the access_type=offline my code never worked and it will never work. Now I wonder why? It would be good to have some explanation.

Facebook authentication shows deprecated method error

I'm using the Facebook C# SDK and trying to authenticate my user. The first part sort of worked, my app showed me the facebook login page inside a browser control.
This is the code I have, I was following this example.
private readonly FacebookClient _fb = new FacebookClient();
private void Browser_Loaded(object sender, RoutedEventArgs e)
{
var loginUrl = GetFacebookLoginUrl();
BrowserControl.Navigate(loginUrl);
}
private Uri GetFacebookLoginUrl()
{
var parameters = new Dictionary<string, object>();
parameters["client_id"] = FacebookSettings.AppID;
parameters["redirect_uri"] = "https://www.facebook.com/connect/login_success.html";
parameters["response_type"] = "token";
parameters["display"] = "page";
if (!string.IsNullOrEmpty(FacebookSettings.ExtendedPermissions))
parameters["scope"] = FacebookSettings.ExtendedPermissions;
return _fb.GetLoginUrl(parameters);
}
After I filled in my details to log into facebook, I got this error:
Any idea's which method is deprecated and how I can fix this?
I used the same code and it's working. And such an error is occuring because of a bug in the facebook API, when display parameter is set to "touch" or "wap". That shouldn't occur when using "page". Try using "popup" as the display.
Try changing the july 2012 Breaking Changes in the app's advanced settings tab(in developer.facebook.com). Refer to this link for information on this issue. And similar issue in facebook developer site.

Resources