I have a MVC application that it's using local AD to authenticate users and get their Roles for set permissions to the application. Now I have a new requirement, I'll use an external AD to authenticate the users rather than the local one. So, my application will redirect users to the client's login page, users will enter username and password that will be validated on their AD and then redirect back to my application with a token. I need to get this token and post once again to the customer endpoint in order to get a JWT token.
The problem is that I could not find a good example of something similar to that. I was trying use Open Id:
app.UseOpenIdConnectAuthentication(new
OpenIdConnectAuthenticationOptions {
ClientId = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
Authority = "https://xx.xxxxxxxxx.xxx/adfs/oauth2/authorize",
RedirectUri = "http://localhost:27100/token",
ResponseType = "code",
Scope = "openid email",
Resource = "xxxxxxxx",
UseTokenLifetime = false,
SignInAsAuthenticationType = "Cookies",
});
but I'm getting the following error:
Unable to create to obtain configuration from:
'https://xx.xxxxxxxxx.xxx/adfs/oauth2/authorize/.well-known/openid-configuration
If I open the full url on my local browser I can see the login page to the customer AD. I'm not sure if OpenIdAuthentication is the right one for this scenario, I was trying this one because is has all the properties that I need to set. Is there any other way to achieve that?
Are you trying to do an on-behalf of authentication?
Refer to https://technet.microsoft.com/en-us/windows-server-docs/identity/ad-fs/development/ad-fs-on-behalf-of-authentication-in-windows-server-2016
For OpenID Connect with AD FS please refer to https://technet.microsoft.com/en-us/windows-server-docs/identity/ad-fs/development/enabling-openid-connect-with-ad-fs-2016
The .well-know/openid-configuration endpoint should resolve to something that looks like:
You probably can just update the Authority property to one of these values (depending on where the STS is running):
"https://xx.xxxxxxxxx.xxx/adfs/"
"https://xx.xxxxxxxxx.xxx/adfs/oauth2"
Related
I have an MVC client app (APP1) protected by Identity Server. I use a backchannel mechanism to log out of clients as soon as user logs out of idsrv. Pretty similar to this one: https://github.com/IdentityServer/IdentityServer4/blob/main/samples/Clients/src/MvcHybridBackChannel/Startup.cs
Now the thing is: I need to add a support for external provider, Azure AD. And in turn it also should support automatic log out: when a user logs out of Azure AD, he should be logged out of idsrv and from the client apps.
My first idea was to implement the same approach: Azure App registration supports the ability to call client's endpoint upon log out. But I'm struggling with the part when I need to set up custom CookieAuthenticationEvents. The code which I have in a client app APP1:
services.AddAuthentication(options =>
{
options.DefaultScheme = "Cookies";
options.DefaultChallengeScheme = "oidc";
}).AddCookie("Cookies", options =>
{
options.EventsType = typeof(CookieEventHandler);
}
But the same code doesn't work in idsrv. But this I mean that my cookie is not being validated by my custom CookieEventHandler. Can anyone point me in a right direction?
One idea is to let Azure AD call the Logout method on the AccountController to sign out the user. (or if you make your own "logout" endpoint).
The logout method is protected by a ValidateAntiForgeryToken, so you might need to get around that by creating your "own" logout endpoint.
But basically what you need to do on a high level is to let AzureAD trigger a call to the
HttpContext.SignOutAsync(); method.
I need to add OpenID Connect authentication to an existing ASP.NET MVC web application. For that, I am using OWIN.
Once the user has been successfully authenticated by the authentication server (Azure Active Directory in my case), I need to check that the user can be mapped to a local account in my web application. If the user has no valid local account, the actual login process should fail. Is there a standard way to do that?
In the sample I have found (https://learn.microsoft.com/en-us/azure/active-directory/develop/tutorial-v2-asp-webapp), it seems that as soon as the user is successfully authenticated by Azure, then it is logged in the application. Can we add custom code to the OWIN-OIDC sign-in process to perform additional checks?
Thanks for your help.
Good question and there are 2 levels here, as you are finding:
Authenticating with the Authorization Server / Identity Provider
Access to the application being allowed
If the first is successful but the second is not, then the standard behaviour is to redirect the user to an 'Access Denied' page (this page must allow anonymous access, to avoid a redirect loop). The login has not failed, but the user is not authorized to access the app.
OWIN uses response_type='code id_token' meaning that you will have an Open Id Connect User Identity to work with. If you can't find the user in your own data you can perform a redirect in the below callback:
var openidOptions = new OpenIdConnectAuthenticationOptions
{
Notifications = new OpenIdConnectAuthenticationNotifications
{
// Point to a callback to check the identity against my own system
// This callback can perform a redirect if the app does not recognise the user
AuthorizationCodeReceived = HandleAuthorizationCodeReceived
}
}
I'm working on an application that, in this point, will retrieve the Office Groups that the logged in user is included and perform actions based on that info.
I'm using oAuth2.0 and the v2.0 token endpoint to get access without a user, and with the code below, I can provide administrator consent to the permissions (which were applied to the application permissions on the new Application Registration Portal https://apps.dev.microsoft.com/ and appear on the Enterprise Applications section on Azure), request the token to Azure and receive it, but even with the permissions applied and that token, I get a 403 response code (Insufficient privileges) from the Graph API to any request I try to perform.
The code for those actions is the following:
// Request Admin Consent
HttpRequestMessage adminConsentRequest = new HttpRequestMessage(HttpMethod.Get, "https://login.microsoftonline.com/" + TenantId + "/adminconsent?client_id="+ClientId+"&redirect_uri=https%3A%2F%2Flocalhost%3A44369%2FHome%2F");
var adminConsentResponse = await client.SendAsync(adminConsentRequest);
// Request Token
HttpRequestMessage tokenRequest = new HttpRequestMessage(HttpMethod.Post, "https://login.microsoftonline.com/"+TenantId+"/oauth2/v2.0/token") { Content = new FormUrlEncodedContent(tokenRequestPairs) };
var tokenResponse = await client.SendAsync(tokenRequest);
string tokenResponseBody = await tokenResponse.Content.ReadAsStringAsync();
var deserializedTokenResponse = (JObject)JsonConvert.DeserializeObject(tokenResponseBody);
string accessToken = deserializedTokenResponse["access_token"].Value<string>();
// Call Microsoft Graph API
HttpRequestMessage graphRequest = new HttpRequestMessage(HttpMethod.Get, "https://graph.microsoft.com/v1.0/me/memberOf");
graphRequest.Headers.Add("Authorization", "Bearer "+accessToken);
var graphResponse = await client.SendAsync(graphRequest);
string graphResponseBody = await graphResponse.Content.ReadAsStringAsync();
var deserializedGraphResponse = (JObject)JsonConvert.DeserializeObject(graphResponseBody);
Enterprise Application permissions on Azure
APP Registration Portal permissions
Can someone guide to any kind of mistake I'm making?
With the authorization token and the permissions applied, I can't see why would I get an AccessDenied response.
It's been more than 48 hours since I applied the permissions, so it's not a sync problem.
Update: So thanks to #juunas I managed to reapply the permissions and the token now shows all the permissions applied on the Application Portal (User.Read.All, Directory.Read.All and Group.Read.All), but the API still returns 403 status code (Authorization_RequestDenied).
I've tried another endpoint without the /me just to make sure that is not a reference problem, but it also returns 403 status code.
One thing that is funny is that the App was registered on the new app portal as I said, and it appears on Enterprise Applications on Azure, but not on my App Registrations, so I can only alter permissions on the new App Portal. It should be like this, since I'm using a new registration portal?
After a discussion in the comments, the problem was fixed by re-consenting the permissions similarly as shown in my blog post: https://joonasw.net/view/the-grant-requires-admin-permission (though it is written for v1).
To run admin consent again, you need to add prompt=admin_consent to the authorize URL.
Okay, so a few minutes after the update on the original post, the token was accepted by the endpoints.
The only problem is that the graph API does not recognize the ID of the user logged in to use the /me endpoints, but I bypassed that using the /{group-id}/members endpoint (in my case, it's not how I wanted but solves my problem).
Thanks #juunas for the help!
I'm trying to build a ASP.NET MVC app which doesn't allow access to anonymous user (with the exception of a custom URL that is to be shown to authenticated users which aren't allowed to use the app).
Now, I've register my app in the azure portal (portal.azure.com) and I'd like to use several URLs. I've added two entries:
https://localhost/test
https://www.test.com
I'm using the following code to configure authentication at startup:
public void ConfigureAuth(IAppBuilder app) {
app.SetDefaultSignInAsAuthenticationType(
CookieAuthenticationDefaults.AuthenticationType);
app.UseCookieAuthentication(new CookieAuthenticationOptions());
app.UseOpenIdConnectAuthentication(
new OpenIdConnectAuthenticationOptions {
ClientId = clientId,
Authority = authority,
PostLogoutRedirectUri = postLogoutRedirectUri,
Notifications = new OpenIdConnectAuthenticationNotifications {
SecurityTokenValidated = VerificaUtilizadorAutenticado,
AuthenticationFailed = TrataErroAutenticacao
}
});
}
Everything seemed to be working fine, but after publishing the app, it seems like I can only use one of the URIs. I've searched and it seems like I can use the RedirectUri property of the OpenIdConnectAuthenticationOptions to set up the reply url. So, I've tried adding this to the setup:
RedirectUri = "https://localhost/test",
Unfortunately, doing that breaks everything and the browser gets stuck between my app and MS' login page. Since the user is logged in, it redirects the user back to my app. However, it seems like setting the RedirectUri prop does not generate the app's authentication cookie, so it sends the user back to the login page.
If I remove the RedirectUri, then I get redirected to the https://www.test.com site, even though I'm trying to access the https://localhost/test web app.
I'm not sure what, but I'm missing something...Can anyone help?
Thanks.
Luis
When you send a user who wants to sign in to the AAD Login Endpoint (https://login.microsoftonline.com), you will need to specify where you want the user (and the Authorization Code) to be redirected back to.
You specify this in two ways:
You must configure a Reply URL in your app's main configuration as a part of app creation.
You must specify a Reply URL in your Login URL, which exactly matches one of the URLs you configured:
From the Authorization Code Grant Flow documentation:
https://login.microsoftonline.com/{tenant}/oauth2/authorize?
client_id=6731de76-14a6-49ae-97bc-6eba6914391e
&response_type=code
&redirect_uri=http%3A%2F%2Flocalhost%2Fmyapp%2F <-- this guy
&response_mode=query
&resource=https%3A%2F%2Fservice.contoso.com%2F
&state=12345
If you do not specify a Redirect URI in your Login URL, the user will be redirected to the first URL specified in your app's registration. That doesn't sound so bad, but know that AAD treats your Reply URLs as an unordered list, so depending on the server you hit, or how data got replicated, you might observe different redirection behaviors across different sign-in attempts. That is why it is important to ALWAYS specify the redirect_uri parameter in your login endpoint.
I feel like many of your problems may be solved if you use the ADAL libraries to authenticate rather than the libraries shown in your sample code, but if you do not want to use these, then you will need to share more details like the HTTP trace of the authentication process.
Ok, after some digging, I've noticed that the problem I was having when setting the redirecturi was that I was missing...a slash (/). So, adding the / to the URL defined on the portal and putting it also in the redirecturi of the options object was enough to make it work against different URI...
We have a scenario where we have a single application that will be accessed from our organization and also accessed from a outside organization. We will be hosting this web application in azure. I am using MVC 5 with the Owin WSFederation Middleware. I can connect to my Local ADFS Server and it works as expected.
app.UseWsFederationAuthentication(
new WsFederationAuthenticationOptions
{
Wtrealm = "https://localhost:44321/",
MetadataAddress = "https://sso2.xxxxx.com/FederationMetadata/2007-06/FederationMetadata.xml"
});
When I use ACS as the Main STS and set up our ADFS server as an IDP, it routes to the correct ADFS login page, but once I authenticate I get this error
ID4037: The key needed to verify the signature could not be resolved from the following security key identifier 'SecurityKeyIdentifier
(
IsReadOnly = False,
Count = 1,
Clause[0] = X509RawDataKeyIdentifierClause(RawData = MIIC4DCCAc...'. Ensure that the SecurityTokenResolver is populated with the required key.
app.UseWsFederationAuthentication(
new WsFederationAuthenticationOptions
{
Wtrealm = "https://localhost:44321/",
MetadataAddress = "https://xxxxxxxx.accesscontrol.windows.net/FederationMetadata/2007-06/FederationMetadata.xml"
});
I feel like this is an issue because the Federated metadata contains the key for the signature and since the owin middleware only has the metadata from the ACS the signer can't be determined.
Thoughts?
Is the realm configured in ACS?
If I was implementing this, then i would probably use ADFS instead of ACS for my Home Realm Discovery because ACS is on it's way out.
I would configure Azure as an additional Claims provider in ADFS and only have my application using ADFS.
You also get a little more control around what the HRD pages look like.