Cannot Logout from IdentityServer 4 through Azure SAML logout request - azure

Context
I have a Service Provider (SP) based on IdentityServer 4 and Sustainsys.Saml2.AspNetCore2 that is configured to use Azure as an IdP (SAML2).
I also have a SPA with an api that connects to my SP (with oidp) to identify my user. The api then creates a JWT for my user to use.
I can login my user correctly.
Question
My issue comes with the logout. I want to use the logout url parameter of Azure to notify my SP about the logout. I manage to see the SAML Logout Request as a string when I configure an endpoint of mine but I can't exploit it and parsing it manually does't seem right.
Is there an existing endpoint that would come with my dependencies that I missed?
The goal here is to revoke all my user's application sessions (the apps to which my user is connected throug my SP).
Configuration
Idp configuration in the SP (called in Startup.cs).
The Saml2AuthModel comes from a config file.
public static AuthenticationBuilder AddSaml2Auth(this AuthenticationBuilder builder, Saml2AuthModel saml2AuthModel)
{
builder.AddSaml2(saml2AuthModel.Scheme, saml2AuthModel.DisplayName ?? saml2AuthModel.Scheme, options =>
{
options.SignInScheme = IdentityServerConstants.ExternalCookieAuthenticationScheme;
options.SignOutScheme = IdentityServerConstants.SignoutScheme;
options.SPOptions.EntityId = new EntityId(saml2AuthModel.ServiceProviderEntityId);
options.SPOptions.ModulePath = "/" + saml2AuthModel.ModulePath ?? saml2AuthModel.Scheme ?? options.SPOptions.ModulePath;
var idp = new IdentityProvider(
new EntityId(saml2AuthModel.IdentityProviderEntityId),
options.SPOptions
);
idp.MetadataLocation = saml2AuthModel.IdentityProviderMetadataLocation;
options.IdentityProviders.Add(idp);
});
return builder;
}

The Sustainsys.Saml2 library has support for single logout. To enable it, you need to set up a service signing key. The reason is that logout requests and responses should be signed. So the library doesn't expose the logout endpoints if it has no signing keys available.

Related

How to use asp.net identity cookie auth along with oidcconnect?

I have an ASP.NET MVC 5 application that uses ASP.NET Identity 2/OWIN that has it's own login using the following:
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
LoginPath = new PathString(AppConfiguration.LoginPath),
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, int>(
validateInterval: TimeSpan.FromMinutes(30),
regenerateIdentityCallback: (manager, user) => user.GenerateUserIdentityAsync(manager),
getUserIdCallback: (id) => (Int32.Parse(id.GetUserId())))
}
});
In Addition to our own authentication set up above in the startup, we'd like to also introduce authentication using an external app that uses Identity Server 4 (basically just so a user in that app can sso into ours), using open id connect, setting that up after the above code like:
app.UseOpenIdConnectAuthentication(new OpenIdConnectAuthenticationOptions
{
Authority = AppConfiguration.ExternalServerAuthority,
ClientId = "xxxxxxxxxx",
ClientSecret = "secret",
RedirectUri = "http://localhost:1045/signin-oidc",
ResponseType = "id_token",
RequireHttpsMetadata = false,
PostLogoutRedirectUri = "http://localhost:1045/signout-callback-oidc",
SignInAsAuthenticationType = "Cookies",
Notifications = new OpenIdConnectAuthenticationNotifications
{
SecurityTokenValidated = async context =>
{
var appAuthManager = DependencyResolver.Current.GetService<IApplicationAuthenticationManager>();
var userManager = DependencyResolver.Current.GetService<IApplicationUserManager>();
var email = context.AuthenticationTicket.Identity.FindFirst("preferred_username");
var user = userManager.FindByName(email.Value, null);
if (user == null)
{
return;
}
await appAuthManager.SignInAsync(user, false, false);
}
}
});
We need to be able to do a SignInAsync when we get the token from the external app because we need the user to be signed in as the actual user in our own app. Part of our problem is also, if we set this up, then whenever a user is not logged in, they are always sent to the other external app to log in if trying to access a resource/page that they must be logged in for - it no longer sends them to our existing login page (which would give them the option of logging in there like they normally would or clicking a link to take them to the other app to log in if they have a user account for that app too). We don't want this because not all our users will be using/have access to this other app, it's really only for some users, mostly to conveniently navigate into our app from the other app without having to separately sign in to ours. So we can't have all unauthorized requests sent to this other app to log in. How can we achieve that? Is there a better way to set that up here?
Edit for more info:
To explain more clearly the pieces here and what needs to happen. There are actually three applications at play. There is our app, an MVC 5 app that has it's own login page, uses owin/asp.net identity for user authentication and to store/manage its users. There is now another app (for another company that wants to work with us), which is a SPA app that authenticates against a separate IdentityServer4 server run by the same company. This SPA app, wants to put a link in it that sends a user to our MVC 5 app without the user having to actually log in to our MVC 5 app - so, they want to SSO into our MVC 5 app (by use setting up our app to use oidc connect to authenticate the user against the SPA's identity server). So when they get to our app, we need to actually log them in as our user....but we have to also make sure that all our users are not sent to this external app to log in when they are not currently logged in to our app because not all our users will have access to this external app. I hope that clears this up.

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

Is it possible to use Azure Mobile App and Azure AD B2C to authenticate localhost web?

I know that local debugging using tokens is possible using http://www.systemsabuse.com/2015/12/04/local-debugging-with-user-authentication-of-an-azure-mobile-app-service/. Would it be possible to go to thesite.com/.auth/login/aad and login and use that cookie for localhost (for testing the web app - not the mobile app)?
I am currently using the .auth/login/aad cookie to authenticate Nancy. I do by generating a ZumoUser out of the Principal.
Before.AddItemToEndOfPipeline(UserToViewBag);
and
internal static async Task<Response> UserToViewBag(NancyContext context, CancellationToken ct)
{
var principal = context.GetPrincipal();
var zumoUser = await ZumoUser.CreateAsync(context.GetPrincipal());
context.ViewBag.User = zumoUser;
context.Items["zumoUser"] = zumoUser;
var url = context.Request.Url;
if (zumoUser.IsAuthenticated)
{
_logger.DebugFormat("{0} requested {1}", zumoUser, url.Path);
}
else
{
_logger.DebugFormat("{0} requested {1}", "Anonymous", url.Path);
}
return null;
}
Yes. You need to read "the book" as it is a complex subject. The book is available open source at http://aka.ms/zumobook and the content you want is in Chapter 2.
Would it be possible to go to thesite.com/.auth/login/aad and login and use that cookie for localhost (for testing the web app - not the mobile app)?
No, this is impossible. The JWT token verification is based on the stand protocol(OpenId connect or Oauth 2) we can follow. But there is no official document or SDK about the the cookie issued by the Easy Auth verification.

Azure AD OpenIDConnect + ASP.NET Core - Authenticate and Extra Permissions/Token?

I am using the following bits against my Azure AD to authenticate with ASP.NET Core.
https://azure.microsoft.com/en-us/resources/samples/active-directory-dotnet-webapp-openidconnect-aspnetcore/
https://github.com/Azure-Samples/active-directory-dotnet-webapp-openidconnect-aspnetcore
I have the basic login/auth working after creating an Azure AD app. User can login/logout.
My question is given this, what's the best way when a user Auth's to log to a DB? I thought about making the redirect URL to an endpoint, saving, then just redirecting back to "Home" but is that ideal?
Also, is it possible to retrieve a bearer token via this approach? Or does this require another type of call or extending "scope"? So that for example I could retrieve the authenticated users Manager.
https://graph.microsoft.com/v1.0/me/manager
My question is given this, what's the best way when a user Auth's to log to a DB? I thought about making the redirect URL to an endpoint, saving, then just redirecting back to "Home" but is that ideal?
This way only able to log those who already sign-in your app successfully. It is not able to log those users who are attempt to sign-in your app but enter the wrong password.
Azure AD already provide lots of report to gain visibility into the integrity and security of your organization’s directory.( refer here)
And if you are using the Azure AD Premium, you can review the sign-in activities via the Azure new portal below:
And if you want to store the sign-in activity in your web app, you can write the custom code after the token is verified. Here is the code for your reference:
// Configure the OWIN pipeline to use OpenID Connect auth.
app.UseOpenIdConnectAuthentication(new OpenIdConnectOptions
{
ClientId = Configuration["AzureAD:ClientId"],
Authority = String.Format(Configuration["AzureAd:AadInstance"], Configuration["AzureAd:Tenant"]),
ResponseType = OpenIdConnectResponseType.IdToken,
PostLogoutRedirectUri = Configuration["AzureAd:PostLogoutRedirectUri"],
Events = new OpenIdConnectEvents
{
OnRemoteFailure = OnAuthenticationFailed,
OnTokenValidated = context => {
//write the custom code to store users login-in
return Task.FromResult(0); }
},
});
Also, is it possible to retrieve a bearer token via this approach?
Yes. We can get the token after receive the authorization code. You can refer the code sample here to acquire the token from asp.net core app.

Azure AD Sign In

I have a web application that is secured by Azure AD. I would like to be able to allow some people to access this application. I have created an account in my directory for these users and I would like to log them in without doing a redirect to Azure AD.
Is there any way to get an Azure auth cookie and allow them to access my application without redirecting them to a login? I know the username / password and would like to be able to do the sign in behind the scenes.
You should be able to use the Resource Owner Credentials flow. Assuming you're using ADAL, you can leverage this sample app to retrieve a token.
Once you have the authentication result, you can use it to build an identity and pass that to the cookie authentication manager (assuming you're using the OWIN cookie authentication middleware).
var claims = new List<Claim>();
claims.Add(new Claim(ClaimTypes.GivenName, result.UserInfo.GivenName));
var id = new ClaimsIdentity(claims,
DefaultAuthenticationTypes.ApplicationCookie);
var ctx = Request.GetOwinContext();
var authenticationManager = ctx.Authentication;
authenticationManager.SignIn(id);
Source: http://brockallen.com/2013/10/24/a-primer-on-owin-cookie-authentication-middleware-for-the-asp-net-developer/

Resources