OpenIDConnect Azure Website hosted in an iFrame within Dynamics CRM Online - azure

I'm trying to get the OpenIDConnect Azure sample from here working within an iFrame in CRM. I've deployed to Azure where login works fine when hitting the site directly.
When I access the site via an iFrame in CRM Online it's displayed fine but when I attempt to login I'm getting the following error:
Microsoft.IdentityModel.Protocols.OpenIdConnectProtocolInvalidNonceException: IDX10311: RequireNonce is 'true' (default) but validationContext.Nonce is null. A nonce cannot be validated. If you don't need to check the nonce, set OpenIdConnectProtocolValidator.RequireNonce to 'false'.
After some investigation I've updated the OWIN middleware configuration to set the RequireNonce false:
app.UseOpenIdConnectAuthentication(
new OpenIdConnectAuthenticationOptions
{
ClientId = clientId,
Authority = authority,
PostLogoutRedirectUri = postLogoutRedirectUri,
ProtocolValidator = new Microsoft.IdentityModel.Protocols.OpenIdConnectProtocolValidator()
{
RequireNonce = false
}
});
When I now try to login I now get the following exception for which I've hit a wall.
Microsoft.IdentityModel.Protocols.OpenIdConnectProtocolException: invalid_request
Any help would be much appreciated. I understand the use of nonce but I'm yet to understand the full implications of disabling it within this use case so getting this working without the need to disable would be ideal.

The authentication experience cannot be iFramed, for security reasons. Also, turning off the Nonce verification is very dangerous - I would strongly advise against it. You can refer to the OAuth2 and OpenId Connect threat models for concrete details on the risks you'll incur in, however the frame busting logic should make the point moot.

Related

Dynamics 365 Business Central Token

I'm attempting to gain access to Business Central Admin Center API, but I'm having some difficulties.
I'm having the idea that it has something to do with the app registration that I have made in the Azure Portal.
I have (as an admin user of the tenant) registered and app and given it "delegated permissions" to "Dynamics 365 Business Central" with access to "Financials.ReadWrite.All".
I have also created a secret for the app.
My problem is that when I try to access the Admin Center API, I get a "403 Forbidden" response, so I assume that I have either forgotten something, I have created my app registration wrong somehow or that my attempt to access the API, is performed in an inaccurate manor.
If I try to examine the token I get, it doesn't show the permissions that I would expect and have seen in other cases (like with MS Graph API), so I'm thinking maybe it's the token that is the problem.
Here is the code that I use to retrieve a token and my attempt to use it afterwards - maybe someone can spot what I'm doing wrong.
Getting the token
var client_id = "removed_for_security_reasons";
var client_secret = "removed_for_security_reasons";
var tenant_id = "removed_for_security_reasons";
var token_url = "https://login.microsoftonline.com/" + tenant_id + "/oauth2/v2.0/token";
var client = new HttpClient();
var content = new StringContent(
"grant_type=client_credentials"+
"&scope=https://api.businesscentral.dynamics.com/.default"+
"&client_id="+ HttpUtility.UrlEncode(client_id) +
"&client_secret="+ HttpUtility.UrlEncode(client_secret));
content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/x-www-form-urlencoded");
var response = await client.PostAsync(token_url, content);
// here i print the token so I can check it with jwt.io.
Attempting to use the token
var client = new HttpClient();
HttpRequestMessage req = new HttpRequestMessage();
req.Method = HttpMethod.Get;
req.RequestUri = new Uri("https://api.businesscentral.dynamics.com/admin/v2.11/applications/businesscentral/environments");
req.Headers.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue(
"Bearer", access_token);
var res = await client.SendAsync(req);
// this results in "403 Forbidden"
There is no further information given as to why this is forbidden, so I'm having a hard time pin pointing what the problem is.
Does anyone have suggestions?
UPDATE 1
OK, so I have tried to follow the description linked. It doesn't describe which permissions box to check though and it's also using PowerShell which I'm not - I'm using C# with HttpClient.
So, to not circle around this any further, please try to explain which to select here (see images) and/or what is wrong/missing.
Image 1 (the app), what is wrong/missing:
Image 2 (permissions 1), what is wrong/missing:
Image 3 (permissions 2), what is wrong/missing: (admin grant doesn't seem to change anything)
After this, I create a client secret and use the code posted initially.
Of cause this isn't working as expected. If the code is wrong, then please point out what the problem is - referring to the description on the web doesn't help me, as it is vague at best.
I think the issue is your combination of delegated permissions and trying to use the client credential flow.
Client credential flow requires application permissions which is also why your delegated permissions are not shown in your token. The client credential flow does not grant you the delegated permissions.
Even though it doesn't seem to be stated directly anywhere that Admin Center API doesn't support client credential flow, I think it is implied in the documentation.
In Using Service-to-Service (S2S) Authentication the Admin Center API is not mentioned in the Feature availability matrix and The Business Central Admin Center API does not mention client credential flow at all and all the example are using user impersonation.
Your App Registration looks okay to me. You will however need to provide the admin consent.
As described in the article I linked above you need to use MSAL (Microsoft Authentication Library). Since you are using C# you need to use MSAL.NET.
I am not an expert on C#, but maybe this quickstart guide could lead you in the right direction.

AAD B2C:Unable to Authenticate web api after changing Authority URL from login.microsoftonline.com to xyz.b2clogin.com

Unable to authenticate Web Api(.Net Core) after changing the Authority URL from login.microsoftonline.com to xyz.b2clogin.com
Authority Old URL: https://login.microsoftonline.com/tfp/xyz.onmicrosoft.com/SignInPolicy/v2.0
Authority New URL: https://xyz.b2clogin.com/tfp/xyz.onmicrosoft.com/SignInPolicy/v2.0
Startup Code
.AddJwtBearer(AzureJwtSchemes.AZURE_ADB2C_AUTHENTICATION_SCHEME, options =>
{
options.Authority = azureB2COptions.Authority;
options.Audience = azureB2COptions.ClientId;
}
Any help will be really appreciated! Thanks!!!
The code in your Azure AD B2C-enabled applications and APIs may refer to login.microsoftonline.com in several places. For example, your code might have references to user flows and token endpoints. Make sure all of them have been updated to your-tenant-name.b2clogin.com.
Reference:
Set redirect URLs to b2clogin.com for Azure Active Directory B2C
Might be caused by another error.
To check what's really happening you can do the ff:
Create your custom method and setup the OnAuthenticationFailed under the options.Event.
Set the Microsoft.IdentityModel.Logging.IdentityModelEventSource.ShowPII to
true
Add a breakpoint to the AuthenticationFailedContext
Should give you an idea on what's wrong.

SaaS App with AzureADB2C: User Flows for Client SSO?

We have a SaaS web app and our clients are requiring SSO authentication for each of them. We are using AzureADB2C and it works great, but now are looking at adding SSO.
I put in the SSO setup into the B2C tenet and it works great, but really messed up our login screen with a "MyCompanySSO" button to log in with, on our customer-facing login screen.
So now my idea is to have a separate user flow that handles each SSO setup. Starting with us. We'd go to MyCompany.OurSaaSApp.us and that'd forward them directly to the user flow endpoint and prompt them to login with their SSO account (AzureAD).
This all seems to try to work, but I'm getting these errors within the AzureADB2C middleware:
Microsoft.AspNetCore.Authentication.OpenIdConnect.OpenIdConnectHandler:Warning: .AspNetCore.Correlation. state property not found.
Microsoft.AspNetCore.Authentication.OpenIdConnect.OpenIdConnectHandler:Information: Error from RemoteAuthentication: Correlation failed..
Then I get pumped out onto a error page and the login fails.
So 2 things...
1.) Am I going in the right direction knowing what we're wanting to accomplish
2.) What do we need to do to resolve this?
Thanks everyone for the help, it's been greatly appreciated.
(note:)
Just to reiterate. The SSO works properly when the custom identity provider is attached to the existing SignUpOrIn UserFlow I have configured in the app. I'm only getting this error when I try to use another UserFlow that I want to use specifically for this SSO.
I'm not sure about that specific error, although "state" parameter is a parameter that your app sends in the request that will be returned in the token for correlation purposes.
Using and different policy for each federation sounds like the right approach, but if you are doing from a single instance of your app, you'll need to modify the OIDC protocol message with the correct authority (ie policy) on redirect.
In your OIDC middleware configuration, set up a handler for the RedirectToIdentityProvider notification. Then handle it with something like:
private Task OnRedirectToIdentityProvider(RedirectToIdentityProviderNotification<OpenIdConnectMessage, OpenIdConnectAuthenticationOptions> notification)
{
//var policy = notification.OwinContext.Get<string>("Policy");
var tenantSegment = notification.Request.Path.Value.Split(new char [] { '/'}, StringSplitOptions.RemoveEmptyEntries)[0];
if (!string.IsNullOrEmpty(tenantSegment) && !tenantSegment.Equals(DefaultPolicy))
{
notification.ProtocolMessage.IssuerAddress = notification.ProtocolMessage.IssuerAddress.ToLower().Replace(DefaultPolicy.ToLower(), $"B2C_1A_{tenantSegment.ToLower()}_SignUpSignInPolicy");
}
return Task.FromResult(0);
}
If you need to inject anything else tenant-related, that would be the place to do it.

GetExternalLoginInfoAsync always returns null when using Okta for authentication

I'm currently trying to get Okta to work with our MVC based application. Unfortunatly I am not the original designer or author of original code. However after some digging I have found that my predecessors work was based on the sustainsys example app "SampleOwinApplication" and this certainly seems to provided the functionality that we require. So I have based my query on this sample that can be obtained from https://github.com/Sustainsys/Saml2
This works with the sustainsys saml stub but now a genuine authentication provider (in this case Okta)
If I configure the application to use the sustainsys stub authentication provider and using Chrome with a plugin to view SAML tokens. I can see the SAML token come back and is presented to the call back as expected:
public async Task<ActionResult> ExternalLoginCallback(string returnUrl)
{
var loginInfo = await AuthenticationManager.GetExternalLoginInfoAsync();
and when it runs loginInfo gets filed in and all works as expetced.
However when I change to configuration to use my Okta app, I get redirected to log in to Okta (as expecected) and I can see successful authentication and a SAML token comes back to my application (as seen in the Chrome plugin). However the above consumer for the callback ends up with a null value in loginInfo.
Further digging into the issue shows that in the Statup.Auth.cs there is the following code:
// Enable the application to use a cookie to store information for the signed in user
// and to use a cookie to temporarily store information about a user logging in with a third party login provider
// Configure the sign in cookie
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
LoginPath = new PathString("/Account/Login"),
Provider = new CookieAuthenticationProvider
{
// Enables the application to validate the security stamp when the user logs in.
// This is a security feature which is used when you change a password or add an external login to your account.
OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<ApplicationUserManager, ApplicationUser>(
validateInterval: TimeSpan.FromMinutes(30),
regenerateIdentity: (manager, user) => user.GenerateUserIdentityAsync(manager))
}
});
app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);
and then the Saml2 authentication is added
app.UseSaml2Authentication(CreateSaml2Options());
So it looks like cookie authentication is being used rather than saml2. If I check for cookies from the sustainsys site I can see them added to the browser and authentication works as expected. However, if I use Okta for authentication, no such cookies get set and the authentication fails.
Removing all the cookie authentication references results in:
A default value for SignInAsAuthenticationType was not found in IAppBuilder Properties. This can happen if your authentication middleware are added in the wrong order, or if one is missing.
So clearly this is required, shifting the call to app.UseSaml2Authentication(CreateSaml2Options()); before app.UseCookieAuthentication in the vain hope of it changing the priority and therefore picking up the SAML token fails and whilst the code runs authentication and the call to AuthenticationManager.GetExternalLoginInfoAsync, always results in a null value being returned regardless of the authentication provider.
So I either need to completely remove the cookie authentication so it is forced to use the saml packet, get Okta to set the necessary cookies or be able to parse the saml 2 token independently rather than relying on AuthenticationManager.GetExternalLoginInfoAsync to do the work.
Any clues/advice is appreciated
See the working configuration I am currently using successfully with Okta for a service provider initiated login:
AuthenticateResult.Succeeded is false with Okta and Sustainsys.SAML2
Unfortunately, it is still not working with an identity provider initiated login.
See: IdP Initiated Login with Sustainsys.SAML2 - AuthenticateResult Has No Information

The given URL is not allowed by Client_id

I have implemented Google authentication with web API 2 and getting following error:
The given URL is not allowed by Client_id 'ngAuthApp' configuration.
This works when I change AllowedOrigin to (localhost) but not working in api.mytouchstones-uat.net in Client table after azure release.
My code is the following:
// Enable the application to use bearer tokens to authenticate users
app.UseOAuthBearerTokens(OAuthOptions);
//Configure Google External Login
googleAuthOptions = new GoogleOAuth2AuthenticationOptions()
{
ClientId = Common.Constant.GoogleClientId,
ClientSecret = Common.Constant.GoogleClientSecret,
Provider = new GoogleAuthProvider()
};
app.UseGoogleAuthentication(googleAuthOptions);
I had the same issue and this was the first google result for me. So I thought I might answer if someone else stumbles upon this question.
I guess you followed this guide, or similar.
Check that your redirect_uri that you send to Facebook/Google etc is the same as the one you have as AllowedOrigin in dbo.Clients.
And make sure that the same uri are allowed in your Facebook/Google appsettings.

Resources