ASP.Net 5 authentication with Azure - claims seemed to have changed - azure-active-directory

Briefly
Should I be using OpenIdConnectDefaults.AuthenticationScheme when authenticating with Azure ADFS?
In more detail
I have an ASP.NET Core application that has recently been upgraded from 3.1 to .NET 5.
Previously, it had been using the following NuGet package:
<PackageReference Include="Microsoft.AspNetCore.Authentication.AzureAD.UI" Version="3.1.9" />
and the following in my StartUp.cs:
services.AddAuthentication(AzureADDefaults.AuthenticationScheme)
.AddAzureAD(options => this.Configuration.Bind("AzureAd", options));
Today, I updated the NuGet package:
<PackageReference Include="Microsoft.AspNetCore.Authentication.AzureAD.UI" Version="5.0.3" />
And immediately received warnings that I was using deprecated/obsolete code.
I was directed to the Microsoft Identity Web page for more information....seemed like a lot to trawl through to find what I wanted.
I did read though that the Visual Studio Preview version had an updated Project Template, so I created a new project and this connected to Azure and I was logged in with my domain credentials. Fantastic!
The relevant NuGet packages it used appear to be:
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="5.0.3" NoWarn="NU1605" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.OpenIdConnect" Version="5.0.3" NoWarn="NU1605" /
<PackageReference Include="Microsoft.Identity.Web" Version="1.1.0" />
<PackageReference Include="Microsoft.Identity.Web.UI" Version="1.1.0" />
So, Authentication done. Now onto Authorization.....
So we have our own home-grown Authorization service. We send the user's identity (from ADFS) to this and it returns what they're allowed to do. This is where things broke....
Our original code for this used the "Upn" claim from the response from Azure ADFS:
Claim? upnClaim = identity.FindFirst(ClaimTypes.Upn);
This returns the claim with the email address.
However, this now returned null.
The following code did get the claim with the email address:
Claim? upnClaim = identity.FindFirst("preferred_username");
So, I could run with this and it would work.....
However, I would like to know if using OpenIdConnectDefaults.AuthenticationScheme is the preferred option for the latest Microsoft Identity and Azure ADFS? The fact that I'm having to use a magic string "preferred_username" rather than ClaimTypes.Upn gives me some doubt.
Does anyone have any deep insight into this?

The fact that I'm having to use a magic string "preferred_username" rather than ClaimTypes.Upn gives me some doubt.
preferred_username is not a magic string, it's documented as one of the claims that AAD adds to the id token payload, see https://learn.microsoft.com/azure/active-directory/develop/id-tokens#payload-claims.
The underlying library used by the ASP.NET Core OpenID Connect provider used to map claims to match well-known claims in the .NET world. Maybe Microsoft.Identity.Web disables that specific behaviour.
I blogged about this a while back at https://mderriey.com/2019/06/23/where-are-my-jwt-claims/.

Related

IdentityServer4 QuickStart Register Issue

I have ASP.NET Core application with IdentityServer4 using ASP.NET Core Identity (based on excellent quickstart).
http://docs.identityserver.io/en/release/quickstarts/6_aspnet_identity.html
In the walkthrough blog they talk about navigating to localhost:5000/Account/Register to create a new user in the Identity db.
When i navigate to that url i get a white page. Furthermore I don't have a Register.cshmtl page or a Register route or anything with the term Register in it.
Did i get the wrong branch? because i am on the release and using core 2.0
I'm new at this and apologize if i'm missing something obvious.
I have run the dotnet ef command but can't see a db anywhere I look - like in sql express or LocalDb.
I am running the Identity server project out of vs17 on port 5000
If i run the MvcClient project I see the home page with the Secure link. If i click that i am directed to the IS4 instance but alice nor bob login will work. (invalid us/pw).
And i can see in the logs that alice and bob users are not being created in-memory
You probably got this by now, but it might interest someone else.
The Quickstart UI repository is not a direct implementation of the tutorials in the IdentityServer4 docs. If you follow the docs, you will first create a new ASP.NET Core MVC application with Individual User Accounts authentication, and that template will create the registration page.
I think your problem is about routing. With scaffolding Identity and specifying routing Your problem will be resolved.
To maintain full control of the Identity UI, run the Identity
scaffolder and select Override all files.
replace
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
with
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1)
.AddRazorPagesOptions(options =>
{
options.AllowAreas = true;
options.Conventions.AuthorizeAreaFolder("Identity", "/Account/Manage");
options.Conventions.AuthorizeAreaPage("Identity", "/Account/Logout");
});
services.ConfigureApplicationCookie(options =>
{
options.LoginPath = $"/Identity/Account/Login";
options.LogoutPath = $"/Identity/Account/Logout";
options.AccessDeniedPath = $"/Identity/Account/AccessDenied";
});
// using Microsoft.AspNetCore.Identity.UI.Services;
services.AddSingleton<IEmailSender, EmailSender>();
Now you can access to Register account page:
http://localhost:5000/Identity/Account/Register
You also can also change default route like what you want (localhost:5000/Account/Register) for this purpose check this post

ADFS/SAML2.0 - How to set Claim Rules through Federation Metadata?

I'm trying to implement a SAML 2.0 authentication against Windows ADFS for a web application. So far I succeeded in authenticating and getting what I need from ADFS by manually configuring the Relying Party Trust and the assigned Claim Rules.
Now I want to provide federation metadata for my application to make it easier to set up the required stuff in ADFS. However I can't figure out how to pass the required Claim Rules in that metadata.
Here's what I have so far:
<?xml version="1.0"?>
<EntityDescriptor xmlns="urn:oasis:names:tc:SAML:2.0:metadata" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" xmlns:ds="http://www.w3.org/2000/09/xmldsig#" entityID="dokuwiki-entity" validUntil="2015-03-24T20:30:16Z">
<SPSSODescriptor protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol" WantAssertionsSigned="true">
<NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:transient</NameIDFormat>
<NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:persistent</NameIDFormat>
<AssertionConsumerService index="1" isDefault="true" Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="https://perd.cosmo/dw-2014-01-13/doku.php?id=start"/>
<AttributeConsumingService index="1">
<ServiceName xml:lang="en">DokuWiki</ServiceName>
<RequestedAttribute isRequired="true" Name="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri" FriendlyName="E-Mail-Adresse" />
</AttributeConsumingService>
</SPSSODescriptor>
<Organization>
<OrganizationName xml:lang="en">DokuWiki</OrganizationName>
<OrganizationDisplayName xml:lang="en">DokuWiki</OrganizationDisplayName>
<OrganizationURL xml:lang="en">https://www.dokuwiki.org</OrganizationURL>
</Organization>
</EntityDescriptor>
From what I understand the RequestedAttribute should tell the ADFS to send me the user's E-Mail address upon authentication. Unfortunately after using this metadata to set up the Relying Party Trust no Claim Rules are set up.
Question: Is it possible to set up Claim Rules through metadata or has this always to be done manually? If it is possible where do I find the appropriate documentation?
You have to setup the claimsrules manually (or through powershell). ADFS does not look at that part of the metadata.

Configuring Breeze web client to connect to remote breeze server with CORS support

We are envisioning a product that will have a web front end and mobile apps on multiple platforms (Xamarin). I've already turned a breeze angular hot towel example into a web front end. I am tasked with investigating splitting apart the breeze web client and the breeze server back end. The main reason for this is the mobile devs could potentially use breeze sharp to save their objects to the same breeze back end. It seems like a bad idea to have the breeze web client and server coupled so tightly. I duplicated the project and stripped out the necessary parts on each end to decouple them.
The part I can't figure out is how to get them to talk to each other again. I briefly looked into connectionString, but that doesn't seem to be the right answer. Any ideas on how to get them talking again would be appreciated.
Edit: 20140725 14:23
I've been trying to resolve this on and off since yesterday. I looked into connectionStrings in Web.config and found that that was dead end. Another post made me think that appSettings in Web.config.
I found a parameter in config.js named remoteServiceName. The previous value was "breeze/Breeze" I changed it to
'http://localhost:4545/breeze/Breeze'
The web client still fails:
Error retrieving data.Metadata query failed for: http://localhost:4545/breeze/Breeze/Metadata; HTTP response status 0 and no message. Likely did not or could not reach server. Is the server running? Error: Metadata query failed for: 'http://localhost:4545/breeze/Breeze/Metadata'; HTTP response status 0 and no message. Likely did not or could not reach server. Is the server running?'
When I run that link in its own tab I get metadata.
What did I strip out?: The breeze controller, models, repository (c# only), dbcontext, and BreezeWebApiConfig
Edit 20140725 14:52
Sorry I missed the exception before the one mentioned above:
XMLHttpRequest cannot load http://localhost:4545/breeze/Breeze/Metadata. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:53555' is therefore not allowed access.
Thank you to everyone for the clues you provided in the comments!
The first part of the answer I already included in my edits above:
I found a parameter in config.js named remoteServiceName. The previous value was "breeze/Breeze" I changed it to
'http://localhost:4545/breeze/Breeze'
That got the client talking attempting to talk to the remote server.
After that the CORS issue stumped me. The three following links helped me solve this issue:
Using Breeze with a WebApi Service from another domain
WebAPI CORS and Ninject
http://msdn.microsoft.com/en-us/magazine/dn532203.aspx
You have to install the CORS packages. From the microsoft article:
First, in order to get the CORS framework, you must reference the CORS libraries from your Web API application (they’re not referenced by default from any of the Web API templates in Visual Studio 2013). The Web API CORS framework is available via NuGet as the Microsoft.AspNet.WebApi.Cors package. If you’re not using NuGet, it’s also available as part of Visual Studio 2013, and you’ll need to reference two assemblies: System.Web.Http.Cors.dll and System.Web.Cors.dll (on my machine these are located in C:\Program Files (x86)\Microsoft ASP.NET\ASP.NET Web Stack 5\Packages).
The next step was to add a few lines to the config file from the webapi-cors-and-ninject stackoverflow post:
<system.webServer>
<handlers>
</handlers>
<httpProtocol>
<customHeaders>
<!-- Adding the following custom HttpHeader will help prevent CORS from stopping the Request-->
<add name="Access-Control-Allow-Origin" value="*" />
<add name="Access-Control-Allow-Headers" value="Content-Type" />
</customHeaders>
</httpProtocol>
Obviously this is a very insecure solution and shouldn't be used for anything other than a development environment.

Why does my Azure application still point to default.aspx?

I have created a PivotViewer application with an Azure Web role, and it deploys on my local machine perfectly. When I deploy it to azure, the standard default.aspx "My ASP.NET" application is the loaded page. I can not seem to find a solution in all of the tutorials. If I point the browser to http://solution.cloudapp.net/MyAzureStartPage.aspx, I can also find a perfect deployment, but I can't seem to get the proper home page.
Determining which page to load if none is explicitly specified is a function of the web server. Without configuration changes, the web server is never going to expect to look for your custom page.
Can you not simply rename your desired start page default.aspx? That would be the simplest approach.
Add defaultDocument element in your web.config under configuration/system.webServer node. Something like this will get your default page defined:
<defaultDocument enabled="true">
<files>
<add value="MyAzureStartPage.aspx"/>
</files>
</defaultDocument>

Accessing SharePoint Web Services over Silverlight

I have a problem to access SharePoint Webservice over Silverlight.
An error occurred while trying to make a request to URI
'http://sample:8000/_vti_bin/Authentication.asmx'.
This could be due to attempting to
access a service in a cross-domain way
without a proper cross-domain policy
in place, or a policy that is
unsuitable for SOAP services. You may
need to contact the owner of the
service to publish a cross-domain
policy file and to ensure it allows
SOAP-related HTTP headers to be sent.
Please see the inner exception for
more details.
Some questions:
How do I correctly deploy clientaccesspolicy.xml over Sharepoint Designer? Simply open site in designer, add file and then publish?
The site where clientaccesspolicy.xml should be deployed use forms authentication. I wasn't able to use Sharepoint Designer to publish there. Because of that, I created new zone for this site, which use Windows Authentication and published clientaccesspolicy.xml there. Both use same content database, didn't ?
If clientaccesspolicy.xml will be published, how can I allow this file be accessed anonymously?
Regards
Anton Kalcik
Here answers to my question 1. and 2.:
In Sharepoint Designer you open the site over: File -> Open Site -> In text field "Site name:" type URL of your site. Than drag & drop clientaccesspolicy.xml in root of your site.
If you have Form Authentication, you don't need for this step create new zone (but for some reasons it can be useful). You simply open web browser and type URL of your site. Then fill up text fields (always with user that have administrator privileges) and check "Sign me in automatically". After that will Sharepoint designer use this credentials for specified URL.
If you can help me with question Nr. 3, or you have some other solution, how can I access clientaccesspolicy.xml from Silverlight, post it!
The way we handled this on our project was to use an HTTP Handler. We put the clientaccesspolicy.xml file in the _layouts directory (which is shared across sharepoint sites) using a feature (you can also just manually copy it there).
Then we added our HTTP handler to the web.config handlers section. In our handler we check to see if the request is for /clientaccesspolicy.xml and if so we rewrite the path:
if (path.ToLowerInvariant() == "/clientaccesspolicy.xml")
{
HttpContext.Current.RewritePath("/_layouts/clientaccesspolicy.xml");
}
I'm not sure if this will bypass the security so it might not fully address your issue. But at least it gives you a method to access this file.
That is fine.
It should be, provided you haven't setup a whole new site somehow.
It shouldn't be as that would be a security risk. If you need to authenticate via WindowsAuth for the services so should you for the clientaccesspolicy.xml.
Keep in mind that clientaccesspolicy.xml must be at the domain root. In your example it would have to availble from http://sample:8000/clientaccesspolicy.xml. If you can't open it from your browser at that URL, your Silverlight client won't find it either.
The easiest way to get the file in the right place is to just copy it there via FTP or explorer. The file should be available to anonymous users (read only of course).
I find more realeable way to implement sharepoint httpHandler: it returns all content of clientaccesspolicy.xml himself
public void ProcessRequest(HttpContext context) {
if (context.Request.Path.ToLowerInvariant() == "/clientaccesspolicy.xml") {
context.Response.Write(#"<?xml version='1.0' encoding='utf-8' ?><access-policy><cross-domain-access> "+
#"<policy> <allow-from http-request-headers='*'> <domain uri='*' /> </allow-from> <grant-to> "+
#"<resource path='/' include-subpaths='true' /> </grant-to> </policy> "+
#"</cross-domain-access> </access-policy>");
}
}

Resources