Using Owin in .Net Core for 3rd Party Authentication - owin

I am trying to use third party sign on authentication in a .net core web application solution I am creating. I am trying to use the Owin package to do so. I have looked at an example of Owin in .net framework, I have been trying to translate this to the .net core application but I have been very unsuccessful.
If someone could point me to an example of a .net core web application that is using Owin for 3rd party authentication it would be greatly appreciated.
Here is the the startup file for a framework web application:
using Microsoft.AspNet.Identity;
using Microsoft.Owin;
using Microsoft.Owin.Security.Cookies;
using Microsoft.Owin.Security.Facebook;
using Microsoft.Owin.Security.Google;
using Owin;
[assembly: OwinStartupAttribute(typeof(Identity.Startup))]
namespace Identity
{
public partial class Startup
{
public void Configuration(IAppBuilder app)
{
ConfigureAuth(app);
}
}
public void ConfigureAuth(IAppBuilder app)
{
// Enable the application to use a cookie to store information for the signed in user
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
LoginPath = new PathString("/Account/Login")
});
// Use a cookie to temporarily store information about a user logging in with a third party login provider
app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);
// Uncomment the following lines to enable logging in with third party login providers
//app.UseMicrosoftAccountAuthentication(
// clientId: "",
// clientSecret: "");
/* app.UseTwitterAuthentication(
consumerKey: "",
consumerSecret: "");*/
app.UseFacebookAuthentication(
appId: "myid",
appSecret: "mysecret");
//app.UseGoogleAuthentication();
}
}
I Want to replicate this in .net core now. However, I cannot reproduce the Microsoft.Owin.Security dependency. I have tried Microsoft.AspNetCore.Owin.Security and it does not resolve.

Related

How to acquire a token with Azure AD and MSAL in ASP.NET

I'm trying to authenticate a token using Azure AD. In a console application, I have no problem with this thanks to IConfidentialClientApplication:
static void Main(string[] args)
{
Console.WriteLine("Making the call...");
RunAsync().GetAwaiter().GetResult();
}
private static async Task RunAsync()
{
AuthConfig config = AuthConfig.ReadJsonFromFile("appsettings.json");
IConfidentialClientApplication app;
app = ConfidentialClientApplicationBuilder.Create(config.ClientId)
.WithClientSecret(config.ClientSecret)
.WithAuthority(new Uri(config.Authority))
.Build();
string[] ResourceIds = new string[] { config.ResourceId };
AuthenticationResult result = null;
try
{
result = await app.AcquireTokenForClient(ResourceIds).ExecuteAsync();
}
...
}
But in a Startup for an ASP.NET Core application, the app uses the standard IApplicationBuilder and the Configure(...) method can't take an IConfidentialClientApplicationBuilder as it doesn't exist.
In Microsoft's documentation, they create a PublicClientApplicationBuilder, but I don't want to start creating entirely new applications in my configuration.
Here is a sample of Startup for ASP.NET Core application for your reference. But as far as I know we can't get token directly in the Startup for ASP.NET Core application with "IApplicationBuilder". "IApplicationBuilder" and "IConfidentialClientApplicationBuilder" are two different concepts.
For your requirement, you can just import modules for msal and use the code you provided above or the code you mentioned in the Microsoft's documentation to get the token.

Secure asp.net core 2.0 webapi with Identityserver3

I am completely new to Identityserver and authorization.
There is an authorization server build using Identityserver3. It works fine with asp.net mvc 5 application.
Now i am trying to use this authorization server to secure the new asp.net core 2.0 webapi.
I couldn't find any good document about how to do this. Can anyone help how to do achieve this?
Thanks
The same way as you will do it if you use IdentityServer 4. In your .NET Core 2.0 Web API, in the Startup.cs :
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddMvcCore()
.AddAuthorization()
.AddJsonFormatters();
services.AddAuthentication("Bearer")
.AddIdentityServerAuthentication(options =>
{
options.Authority = "<identityserverurl>";
options.RequireHttpsMetadata = false;
options.ApiName = "mynetcoreapi";
});
}
public void Configure(IApplicationBuilder app)
{
app.UseAuthentication();
app.UseMvc();
}
}
and of course you need IdentityServer4.AccessTokenValidation package, but it is a .NET Core package, so you shouldn't have any problems.
PS: Don't forget to setup logging (if it is not already done) in your IdentityServer. Helps a lot

Multi-tenant Azure Mobile App service calls failing with 401.71

To preface this, I'm new to Azure programming and Azure AD authentication and I've been following tutorials I've found at various sites (including MS) to get me this far. I'm using Xcode v7.2, ADAL for iOS v1.2.4, Visual Studio 2015 Update 1, and the Azure App Service Tools v2.8.1.
I have an existing native iOS app that I need to be able to authenticate multiple Azure Active Directory instance users through. These users are internal and external (customers who sign up for our services). To that end, I've experimentally implemented the following high level architecture:
Native Client App (iOS / obj-c) -> ADAL iOS library -> (Azure AD authentication) -> Azure Mobile App (service layer)
The iOS app utilizes the ADAL iOS library to acquire an access token which it uses to call authorized Web API services in the Azure Mobile App project.
I'm able to authenticate users from two tenants (an internal Azure AD and an external Azure AD), but only users in the same tenant as the service (internal) are able to call the authenticated APIs. The test user account I used from the external tenant is set up as a Global Admin and I am presented with the appropriate consent view in the native app when authenticating. I can then click through the consent and I receive an access token. When using that token to call a test API however, I get a 401 back. The verbose logs for the Azure Mobile App on the server show the following messages (all URLs below are https, I just don't have the rep to post them as such):
2016-01-12T13:00:55 PID[7972] Verbose Received request: GET MyAzureMobileApp.azurewebsites.net/api/values
2016-01-12T13:00:55 PID[7972] Verbose Downloading OpenID configuration from sts.windows.net/<internal AD GUID>/.well-known/openid-configuration
2016-01-12T13:00:55 PID[7972] Verbose Downloading OpenID issuer keys from login.windows.net/common/discovery/keys
2016-01-12T13:00:56 PID[7972] Warning JWT validation failed: IDX10205: Issuer validation failed. Issuer: 'sts.windows.net/<external AD GUID>/'. Did not match: validationParameters.ValidIssuer: 'sts.windows.net/<internal ad guid>/' or validationParameters.ValidIssuers: 'null'..
2016-01-12T13:00:56 PID[7972] Information Sending response: 401.71 Unauthorized
I've read in several posts that you can disable the token issuer validation in your service by setting the ValidateIssuer parameter in TokenValidationParameters to false. I've tried to do this, but it doesn't seem to have any effect. Here is the code from my Azure Mobile App project:
The startup code:
// Startup.cs
using Microsoft.Owin;
using Owin;
[assembly: OwinStartup(typeof(MyAzureMobileApp.Startup))]
namespace MyAzureMobileApp
{
public partial class Startup
{
public void Configuration(IAppBuilder app)
{
ConfigureMobileApp(app);
ConfigureAuth(app);
}
}
}
The code for the MobileApp -- this should be stock, as generated by the Azure Mobile App project template:
// Startup.MobileApp.cs
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data.Entity;
using System.Web.Http;
using Microsoft.Azure.Mobile.Server;
using Microsoft.Azure.Mobile.Server.Authentication;
using Microsoft.Azure.Mobile.Server.Config;
using MyAzureMobileApp.DataObjects;
using MyAzureMobileApp.Models;
using Owin;
namespace MyAzureMobileApp
{
public partial class Startup
{
public static void ConfigureMobileApp(IAppBuilder app)
{
HttpConfiguration config = new HttpConfiguration();
new MobileAppConfiguration()
.UseDefaultConfiguration()
.ApplyTo(config);
// Use Entity Framework Code First to create database tables based on your DbContext
Database.SetInitializer(new MobileServiceInitializer());
MobileAppSettingsDictionary settings = config.GetMobileAppSettingsProvider().GetMobileAppSettings();
if (string.IsNullOrEmpty(settings.HostName))
{
app.UseAppServiceAuthentication(new AppServiceAuthenticationOptions
{
// This middleware is intended to be used locally for debugging. By default, HostName will
// only have a value when running in an App Service application.
SigningKey = ConfigurationManager.AppSettings["SigningKey"],
ValidAudiences = new[] { ConfigurationManager.AppSettings["ValidAudience"] },
ValidIssuers = new[] { ConfigurationManager.AppSettings["ValidIssuer"] },
TokenHandler = config.GetAppServiceTokenHandler()
});
}
app.UseWebApi(config);
}
}
public class MobileServiceInitializer : CreateDatabaseIfNotExists<MobileServiceContext>
{
protected override void Seed(MobileServiceContext context)
{
List<TodoItem> todoItems = new List<TodoItem>
{
new TodoItem { Id = Guid.NewGuid().ToString(), Text = "First item", Complete = false },
new TodoItem { Id = Guid.NewGuid().ToString(), Text = "Second item", Complete = false }
};
foreach (TodoItem todoItem in todoItems)
{
context.Set<TodoItem>().Add(todoItem);
}
base.Seed(context);
}
}
}
The authentication startup code:
// Startup.Auth.cs
using System;
using System.Collections.Generic;
using System.Configuration;
using System.IdentityModel.Tokens;
using System.Linq;
using Microsoft.Owin.Security;
using Microsoft.Owin.Security.ActiveDirectory;
using Owin;
namespace MyAzureMobileApp
{
public partial class Startup
{
// For more information on configuring authentication, please visit http://go.microsoft.com/fwlink/?LinkId=301864
public void ConfigureAuth(IAppBuilder app)
{
app.UseWindowsAzureActiveDirectoryBearerAuthentication(
new WindowsAzureActiveDirectoryBearerAuthenticationOptions
{
Tenant = ConfigurationManager.AppSettings["ida:Tenant"],
AuthenticationMode = AuthenticationMode.Active,
TokenValidationParameters = new TokenValidationParameters()
{
ValidAudience = ConfigurationManager.AppSettings["ida:Audience"],
ValidateIssuer = false
}
});
}
}
}
The service implementation:
using System.Web.Http;
using Microsoft.Azure.Mobile.Server.Config;
namespace MyAzureMobileApp.Controllers
{
// Use the MobileAppController attribute for each ApiController you want to use
// from your mobile clients
[MobileAppController]
// Use the MobileAppController attribute for each ApiController you want to use
// from your mobile clients
[Authorize]
public class ValuesController : ApiController
{
// GET api/values
public string Get()
{
return "GET returned: Hello World!";
}
// POST api/values
public string Post()
{
return "POST returned: Hello World!";
}
}
}
And my appSettings section in web.config:
<appSettings>
<add key="PreserveLoginUrl" value="true" />
<!-- Use these settings for local development. After publishing to your
Mobile App, these settings will be overridden by the values specified
in the portal. -->
<add key="MS_SigningKey" value="Overridden by portal settings" />
<add key="EMA_RuntimeUrl" value="Overridden by portal settings" />
<!-- When using this setting, be sure to add matching Notification Hubs connection
string in the connectionStrings section with the name "MS_NotificationHubConnectionString". -->
<add key="MS_NotificationHubName" value="Overridden by portal settings" />
<add key="ida:ClientId" value="-- MyAzureMobileApp App ID from Azure AD --" />
<add key="ida:Tenant" value="InternalTestAD.onmicrosoft.com" />
<add key="ida:Audience" value="https://InternalTestAD.onmicrosoft.com/MyAzureMobileApp" />
<add key="ida:Password" value="-- password value removed --" />
</appSettings>
I don't see a place to specify valid token issuers except as a property of the TokenValidationParameters collection in WindowsAzureActiveDirectoryBearerAuthenticationOptions.
According to my understanding of the code, I should have issuer validation disabled, but I have tried adding the external Azure AD STS URL here. Unfortunately, it doesn't seem to have any effect.
Does anybody know if this code is getting ignored or overridden for some reason? Is there some other setting I've missed to either disable issuer validation altogether, or specify a list of valid issuers?
I can certainly provide more information as requested, I'm just not sure what else might be relevant.
Thanks!
I believe I have found the cause of my validation logic being ignored. In the setup of my web api site in Azure App Services, I specified the primary tenant issuer URL by populating the Issuer URL textbox in the "Authentication/Authorization" > "Azure Active Directory Settings" blade. It turns out that when you're going to have more than one issuer (as in my multi-tenant scenario) you should leave this field blank.
It makes perfect sense that the JWT will validate against the issuer you provide in that textbox. What is not so intuitive to me is that you should leave it blank when you have more then one issuer. Maybe MS could add that in to the information bubble above it? Either that or provide some mechanism for allowing multiple issuer URLs.
Hopefully this saves someone else some time with this issue.
Just want to point out that if you have configured the authentication, and you had set the primary tenant issuer URL, and then you turned off this type of authentication, the API still reads from it. Clearing this field worked for me, though I never would have thought so, since I was no longer using AD authentication.

Azure Mobile Services custom authentication with MVC5

I've successfully setup a custom authentication process with Azure Mobile Services and my Windows Phone 8.1 app (following the guide here)
I'm now creating an MVC5 single page application (SPA) to manage the admin side of things for the system. I'm relatively new to MVC5 and just need a little help to get started with performing a login just like in my phone app?
Currently my phone app performs a login by
App.MobileService.CurrentUser = await AuthenticateAsync(this.textBox_email.Text, textBox_password.Password);
which does
private async Task<MobileServiceUser> AuthenticateAsync(string username, string password)
{
// Call the CustomLogin API and set the returned MobileServiceUser
// as the current user.
var user = await App.MobileService
.InvokeApiAsync<LoginRequest, MobileServiceUser>(
"CustomLogin", new LoginRequest()
{
UserName = username,
Password = password
});
return user;
}
this all works well so I guess the question is how do I do make a call to my customer authentication API in the same way in MVC5 and set the user context if successful?
Startup.Auth.cs:
public partial class Startup
{
public void ConfigureAuth(IAppBuilder app)
{
// Enable the application to use a cookie to store information for the signed in user
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
LoginPath = new PathString("/Account/Login")
});
// Use a cookie to temporarily store information about a user logging in with a third party login provider
app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);
// Uncomment the following lines to enable logging in with third party login providers
//app.UseMicrosoftAccountAuthentication(
// clientId: "",
// clientSecret: "");
//app.UseTwitterAuthentication(
// consumerKey: "",
// consumerSecret: "");
//app.UseFacebookAuthentication(
// appId: "",
// appSecret: "");
//app.UseGoogleAuthentication();
}
Let me know if I'm missing any info or detail.
Thanks!
Unfortunately this is not easy to do in Mobile Services. While you could achieve login using the Mobile Services HTML/JS SDK (served in an MVC view), this will not set the user context.
Because of Mobile Services incompatibility with MVC (addressed in the new Mobile Apps product), you won't be able to rely on that SDK. Unfortunately that means writing custom middleware/filters.
The easiest solution is probably to package your username/password validation and storage logic into code that can be shared by your Mobile Services project and your MVC project. The MVC project would need to take the validated user and issue a session cookie which is then read by a custom middleware or filter.
Writing an AuthorizationFilter implementation will be much easier than an OWIN middleware, so I would recommend that approach. Check if the cookie is present and valid, and if so set the user context.

OWIN Sharing claims between WebAPI and MVC Application

The current application that we are developing consists of 2 applications. A WebApi application, and a MVC frontend application. For the WebApi i added support for bearer token authorization via OWIN. These applications run as seperate websites within the same domain but with their own subdomains site.xxx.xxx, api.xxx.xxx
Authenticating to the WebAPi, f.e. with Postman, works as designed, the principal and identity objects, including the claims, are initialized properly.
The question arises when i want to login to the WEbApi from within the Mvc application.
Is there any way to get the ClaimsPrincipal and the ClaimsIdentity in our MVC application after logging in via the WebAPI via the /token url somewhat sharing the OWIN context, or should we implement the same OWIN authorization functionality inside the MVC application to create a seperate autorization "route"?
Yes, there is. Couple things to note
The token you get back from the web api will be encrypted by default. Your web application needs to decrypt this token to be able to extract the claims from the bearer token. For this, you have to have the same machine key on both of the servers (your webapi web.config and mvc web.config needs to have the same machine key)
Your MVC web app needs to wire up both bearer tokens and application cookies. Your startup.auth.cs might include something like this:
public static OAuthBearerAuthenticationOptions OAuthBearerOptions { get; private set; }
static Startup()
{
OAuthBearerOptions = new OAuthBearerAuthenticationOptions();
}
public void ConfigureAuth(IAppBuilder app)
{
app.UseOAuthBearerAuthentication(OAuthBearerOptions);
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
LoginPath = new PathString("/Account/Login")
});
}
Now in your login method
//Assume that the token that you got from web api is in the variable called accessToken
//Decrypt this token first. If your machine keys are the same, the following line will work
var unencryptedToken = Startup.OAuthBearerOptions.AccessTokenFormat.Unprotect(accessToken);
//Next, extract the claims identity from the token
var identity = unencryptedToken.Identity;
//Need to create a claims identity that uses a cookie (not a bearer token). An MVC app
//knows how to deal with a claims identity using an application cookie, but doesn't know
//how to deal with a claims identity using a bearer token. So this is a translation step
//from a web api authentication mechanism to the mvc authentication mechanism
var id = new ClaimsIdentity(identity.Claims, DefaultAuthenticationTypes.ApplicationCookie);
//At this moment, your new claims identity using an application cookie is ready, but we still
//need to sign in. Use the OWIN Auth manager from the context to sign in. This will create
//the application cookie and correctly populate User.IsAuthenticated(). From now on, you are
//logged in
AuthenticationManager.SignIn(id);

Resources