Azure ACS with ADFS Server - asp.net-mvc

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.

Related

How get Azure KeyVault secret for C# IIS application running on premise

Is there any way to get a key vault secret using the IIS app pool identity to authenticate?
The typical solution for reading values from Azure KeyVault is
AzureServiceTokenProvider azureServiceTokenProvider = new AzureServiceTokenProvider();
keyVaultClient = new KeyVaultClient(new KeyVaultClient.AuthenticationCallback(azureServiceTokenProvider.KeyVaultTokenCallback));
result = await keyVaultClient.GetSecretAsync(secretUrl).ConfigureAwait(false);
While this work under visual studio, and even for a Windows/console application, it doesn't work for an IIS application - even when the app pool is configured with an identity that would otherwise work.
All the solutions I've found to date require a service principle and supplying its id and secret which - and it's storing secrets locally that I'm trying to avoid.
Example: https://blog.bitscry.com/2019/02/13/using-azure-key-vault-in-a-console-application/
var keyClient = new KeyVaultClient(async (authority, resource, scope) => {
var adCredential = new ClientCredential(clientId, clientSecret);
var authenticationContext = new AuthenticationContext(authority, null);
return (await authenticationContext.AcquireTokenAsync(resource, adCredential)).AccessToken;
});
Is there any way to get a key vault secret using the IIS app pool identity to authenticate?
For local development authentication, AzureServiceTokenProvider fetches tokens using Visual Studio, Azure command-line interface (CLI), or Azure AD Integrated Authentication.
Using Visual Studio and Azure CLI both need to sign in to azure. And the User should be add to Access Policy of Azure keyvault.
Using Azure ad Integrated authentication, you also need to add the service principal into the Access Policy .
However, if you want to use IIS app pool identity to authenticate, you could not add Application Pool Identity Accounts to Azure keyvault. So, you could not avoid to use service principal's id and secret to authenticate.

Owin Facebook Login failure on MVC Azure Production site ONLY

The short version:
I have an MVC5 website app deployed as an Azure cloud service web role. Using Owin for a login flow. The Owin Facebook integration works fine when testing the site on localhost, but on the production server GetExternalLoginInfoAsync() is returning null in the callback from signin-facebook.
Some details:
Have all the latest Owin Nuget packages (4.0.1 other than Identity.Owin 2.2.2 and Owin (startup components) 1.0).
The app uses basic Owin cookie authentication (traditional logins work fine).
We are not using the default Owin SigninManager, or UserManager as per the MVC WebApplication template. (Failure occurs well before reaching any of that code, in theory!)
Testing using Chrome on Windows 10.
It works perfectly on localhost (both debug and release), directly running the web project from visual studio (no cloud service involvement).
Am using the same Facebook test user for both localhost and production.
On the Facebook end, everything looks normal and the app is added to the user's list of apps, with all the permissions. It's not a facebook rejection.
Went so far as to remove Application Insights (as that is something different in production), but it did not affect the problem.
Looking at DevTools in Chrome:
Cache control looks normal for everything, all no-cache.
The .AspNet.Correlation.Facebook cookie is set and is being returned (same value) to the signin-facebook endpoint on completion from Facebook. Note that there is no other Owin related cookie.
Re. Deployment:
The Azure cloud service consists of the single web role.
Azure cloud service osFamily="5" osVersion="*"
Deployment is done directly from Visual Studio to the staging slot (right click publish).
I typically perform an interactive login to the staging slot, and when things are warmed up I use the Azure portal to swap the slots. Testing of the Facebook login is only on the production slot (not staging).
Here is a code fragment showing the processing (ChallengeResult is per the current WebApplication template code). The Controller is marked as [OutputCache(Location = OutputCacheLocation.None)] and is not marked for [Authorize]:
// POST: /Membership/ExternalSignupDispatch (They clicked to login with Facebook, Google, etc.)
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult ExternalSignupDispatch(string provider, string community = Communities.Dating)
{
// Request a redirect to the external login provider
return new ChallengeResult(provider, Url.Action("ExternalSignupCallback1", "Membership", new { community }));
}
// GET: /Membership/ExternalSignupCallback
public async Task<ActionResult> ExternalSignupCallback1(string community = Communities.Dating)
{
var info = await AuthenticationManager.GetExternalLoginInfoAsync();
if (info == null) // Unsuccessful login
{
The silent failure of Owin/Facebook on the production server is maddening. If only there were an error enumeration... or an exception... but alas
Any ideas are greatly appreciated!
So. It turns out that Owin will currently fail in mysterious manners if there is no pre-existing ASP.NET_SessionID cookie present. Without it, the signin-facebook function does not remove the .Aspnet.Correlation.Facebook cookie, and does not set the .Aspnet.ExternalCookie cookie. The non-presence of the Session ID cookie somehow prevents the required cookie processing from taking place. All this sets the stage for intermittent silent failures, depending on the client's cookie status.
The workaround is to store a fake Session variable when generating the form with the Facebook login, forcing creation of the SessionID cookie prior to any Owin logins.
Note we are using the SystemWebCookieManager (in the hopes of avoiding such cookie issues). It appears that things are still evolving.
For reference, here is the cookie setup in our ConfigureAuth function:
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
CookieManager = new SystemWebCookieManager(),
AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
ExpireTimeSpan = TimeSpan.FromMinutes(Params.LoginExpiryMinutes),
SlidingExpiration = true,
LoginPath = new PathString("/Login"),
Provider = new CookieAuthenticationProvider // Used to allow returning 401 Unauthorized status to API calls, instead of 302 redirect
{
OnApplyRedirect = ctx =>
{
if (!IsAjaxRequest(ctx.Request))
{
ctx.Response.Redirect(ctx.RedirectUri);
}
}
}
});
app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);

Double authentication with Web app & Web API needed?

I'm stuck on how to solve following problem.
I'll start with describing what my app looks like in a general context.
[ ASP MVC (Angular App) ]
Uses Owin cookie
[ WEB API 2 ]
Uses Oauth Token Bearer
This scenario is happening:
User visits app and authenticates with a login form which lies in ASP MVC app and generates a cookie.
Now I've decided to use AngularJs to add a couple features which made me use $resources and Web API 2. However, those features are only available if user is authorized.
To the problem: Now I must use a token for each request to the Web Api 2 to access different methods within controllers. This means I must login the user again but this time through AngularJs. Using /token route.
How would I do this?
Should I take the cookie, check credentials in it and send it as a authentication request?
Can I do something within the form authentication, in the same method, in the Asp MVC app?
Please help me, this gave me a lot of overhead. Walking from a simple app to this in 30min. Can't even get my head around all stuff in the authentication.
Regards!
My WebAPI supports both token and cookie auth.
During startup I register the authentication like this:
private void ConfigureAuth(IAppBuilder app)
{
//Token
app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions
{
});
// 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"),
Provider = new CookieAuthenticationProvider
{
OnApplyRedirect = ctx =>
{
// this is to ensure that a 401 response is sent if the
// user is not authenticated, rather than redirecting to
// a logon page.
}
},
CookieDomain = ".example.com" //might not need to set this
});
}

Secure 2 different web applications with one identify service

Secure 2 different web applications with one identify service
Identity Service: Thinktecture Identity Service V2
Application 1: Asp.net MVC 5 application
Application 2: Asp.net Web API application
The above Applcation 1 and Application 2 are different projects and hosted in different servers. Now my scenarios are
1. Want to secure Application 1 with Identity Service.
2. Want to secure Application 2 with Identity Service.
Use case 1: If user access Application 1 it should redirect to identity service login page, once I entered the credentials and login in to application 1, the same token allow me to access Application 2.
Use case 2: If user try to access any API from Application 2 without login into Identity service, the request should reject.
I found a way to do this using pure SAML tokens. The trick is you need to create a delegation account in Identity Server to allow your web app to delegate identity to a specific realm (where your service lives). Then in the web app you make a service call using the the token that the user already has to get a new token which you use to access your service.
I asked a very similar question and answered it myself here.
Ok. I did eactly the same thing just now. Everything required to get that done is written here. If you're using IdentityServer, you need to configure the Token Type of your RP to be JWT:
this allows you to later extract the token from your authenticated MVC 5 application (see the link above to see how to do this) and then send that token to your Web API. You then need to tell you web api to accept that token, using Microsoft's JwtSecurityTokenHandler class. This class has a ValidateToken() method which accepts 2 parameters, the first being the access token that you put into your auth headers of the requests to the Web API, and the second, the validation parameters are basically what you've defined in IdentityServer's config:
validationParams = new TokenValidationParameters
{
AllowedAudiences = _allowedAudiencesAndSigningKeys.Select(x => x.Key),
ValidIssuer = ConfigurationManager.AppSettings["IssuerIdentity"],
ValidateIssuer = true,
SigningTokens = _allowedAudiencesAndSigningKeys.Select(x => new BinarySecretSecurityToken(Convert.FromBase64String(x.Value)))
};
The Audience(s)/Realm(s) you want to allow access to, the issuer name (your Identity Server name) and the signing symmetric key(s) of the applications you have defined in Identity Server and want to grand access to. The ValidateToken() method returns an ClaimsPrincipal with a list of the claims extracted from the token. The code to do all this can be put in a message handler:
public static void Configure(HttpConfiguration config)
{
var authNConfig = new AuthenticationConfiguration();
config.MessageHandlers.Add(new MyTokenValidationHandler());
}

ASPNet Identity Authentication MVC5 Client web site->Auth Server-> Web API server

I'm a newbie for ASPnet identity services and we require a following requirement.
Following is the architecture setup
1. Appserver
Appsever having
a. Entity Framework
b. ASP.Net Web API2 Odata services
c. Authorization server
2. Webserver
ASP.Net MVC 5 application (Client which access the App server)
The flow needs to be
MVC5 Cleint application having a login / Register form
While register / login the information needs to send to the authorization server int he app server, Authorize and creating the claims using Identity Services.
Once the Identity has been created in the Authorization server, the client application should logged in
I'm aware of getting bearer token from authentication server and that will be used as header information to access the API service
All we are lacking is the MVC client application should use the same identity claims that have created in the Authorization server.
Is there any way to access the claims which are created in the auth server.
I have got some samples about how to authenticate in the auth server and receiving token though OWIN and from this token we can access the API securely but I need of the client web application needs to sign in based on the token
I have gone through the following links
http://blogs.msdn.com/b/webdev/archive/2013/09/20/understanding-security-features-in-spa-template.aspx
Also, I require to add claims when ever it requires after login as well
I have resolve this issue as follows, but I'm not sure this is the effective method
Once log-in and retrieve the bearer token (this token should assigned with claims identity already such as username, role .. etc)
In the web api AccountController, need to create a method to retrieve the default claims which requires for client web application. Please check the follows
[Authorize]
[HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)]
[Route("UserInfo")]
public UserInfoViewModel GetUserInfo()
{
var firstname = ((ClaimsIdentity)User.Identity).Claims.Where(c => c.Type.Equals("FirstName")).SingleOrDefault();
var lastname = ((ClaimsIdentity)User.Identity).Claims.Where(c => c.Type.Equals("LastName")).SingleOrDefault();
var IsApproved = ((ClaimsIdentity)User.Identity).Claims.Where(c => c.Type.Equals("IsApproved")).SingleOrDefault();
var userinfo = new UserInfoViewModel
{
UserName = User.Identity.GetUserName(),
FirstName = firstname.Value.ToString(),
LastName = lastname.Value.ToString(),
UserApproved = Convert.ToBoolean(IsApproved.Value.ToString()),
HasRegistered = externalLogin == null,
LoginProvider = externalLogin != null ? externalLogin.LoginProvider : null
};
return userinfo;
}
From the client, this actin will be called through the token as a header.
Once we have got the information (is in Json string format) needs to serialize with the UserInfoViewModel class (user defined viewmodel is based on the info we require and send from webapi account) with javascript serializer
Using these viewmodel information, assign them to local storage and using (cookies for my case) as a identity at local
keep logout webapi too when ever you logs out from web app.
Please let me know if you need more info or code

Resources