I am developing application in MVC and i want to authenticate my users with Azure active directory.
To achieve this, I have created application in Azure active directory with the application URL and also assigned permissions to application.
I have also configured my application to use Azure AD authentication. Now when i try to access the bootstrapContext.Token, it comes always null.
I am using below method to access the bootstrapContext.
var bootstrapContext = ClaimsPrincipal.Current.Identities.First().BootstrapContext as System.IdentityModel.Tokens.BootstrapContext;
string userAccessToken = bootstrapContext.Token;
I have searched on this and found that i have to update my web.config. So i have updated it as below
<system.identityModel>
<identityConfiguration saveBootstrapContext="true">
<system.identityModel>
My main goal is to use UserAssertion for authContext.AcquireToken method.
And UserAssertion requires bootstrapContext.Token.
As per suggestion from MvdD, I have also tried below thing
app.UseWsFederationAuthentication(
new WsFederationAuthenticationOptions
{
Wtrealm = realm,
MetadataAddress = metadataUri,
TokenValidationParameters = new TokenValidationParameters
{
SaveSigninToken = true
}
});
but now, i am getting below error
AADSTS50027: Invalid JWT token. AADSTS50027: Invalid JWT token. Token format not valid.
Trace ID: 0d052707-9aaf-4037-b7c9-4c4aa7cfcc72
Correlation ID: 9a00573b-cfe9-4665-ab81-c0a03eace9d8
Timestamp: 2016-02-08 05:18:01Z
So can anyone help me on this ?
It's not really clear from your question which protocol or what libraries you are using.
If you are using Katana middleware, you should set the SaveSigninToken property in the appropriate AuthenticationOptions class. For the WS-Federation protocol, it would look something like this:
app.UseWsFederationAuthentication(
app.UseWsFederationAuthentication(
new WsFederationAuthenticationOptions
{
Wtrealm = realm,
MetadataAddress = metadataUri,
TokenValidationParameters = new TokenValidationParameters
{
SaveSigninToken = true
}
}
);
If you are using System.IdentityModel, you need to set the SaveBootstrapContext property on the IdentityConfiguration object.
Related
It states here
that going forward, we must prefer the auth code flow method since "With the plans for third party cookies to be removed from browsers, the implicit grant flow is no longer a suitable authentication method."
I have set up an asp.net mvc 4 web application according to the sample app here. It works when I set up my app registration in AD B2C directory for Access Tokens (used for implicit grant flows). If I switch to "ID Tokens (for implicit and hybrid flows)" as the documentation recommends, I get error that my application is not setup for it.
As I understand from the documentation, I would have to specifiy separate endpoins for /authorize and/token to fetch a token after authorization. I am not sure from looking at the sample though how exactly I can do this. Below is the ConfigureAuth method as you can see in the sample code on github link provided:
public void ConfigureAuth(IAppBuilder app)
{
// Required for Azure webapps, as by default they force TLS 1.2 and this project attempts 1.0
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
// ASP.NET web host compatible cookie manager
CookieManager = new SystemWebChunkingCookieManager()
});
app.UseOpenIdConnectAuthentication(
new OpenIdConnectAuthenticationOptions
{
// Generate the metadata address using the tenant and policy information
MetadataAddress = String.Format(WellKnownMetadata, Tenant, DefaultPolicy),
// These are standard OpenID Connect parameters, with values pulled from web.config
ClientId = ClientId,
RedirectUri = RedirectUri,
PostLogoutRedirectUri = RedirectUri,
// Specify the callbacks for each type of notifications
Notifications = new OpenIdConnectAuthenticationNotifications
{
RedirectToIdentityProvider = OnRedirectToIdentityProvider,
AuthorizationCodeReceived = OnAuthorizationCodeReceived,
AuthenticationFailed = OnAuthenticationFailed,
},
// Specify the claim type that specifies the Name property.
TokenValidationParameters = new TokenValidationParameters
{
NameClaimType = "name",
ValidateIssuer = false
},
// Specify the scope by appending all of the scopes requested into one string (separated by a blank space)
Scope = $"openid profile offline_access {ReadTasksScope} {WriteTasksScope}",
// ASP.NET web host compatible cookie manager
CookieManager = new SystemWebCookieManager()
}
);
}
I am developing an app with .NET Core Web API, Entity Framework and React. I've been reading a lot recently about possible authentication techniques for my API and I've discovered that plain JWT is not entirely secure, so at first I decided to use OpenID Connect with IdentityServer 4. I understand the idea behind OAuth 2.0 and OpenID Connect is to hide user credentials during login process and to involve external authentication provider in issuing an access token, but I don't want to rely on such services because not everyone have an account on Facebook etc. I consider this as an optional way to login. I want to give users an ability to sign in with just login and password. So what is the best (secure) way to accomplish this in modern web apps?
Having project 1 as Client App, project 2 as API Resources and project 3 as Authorization Service (IdentityServer4), I consider following scenarios:
A user is able to create an account on Authorization Service which is responsible for issuing a token required to get access to API Resources through Client App. Authorization Service is registered as authorization provider only for my Client App.
Get authorization token from Authorization Service using resource owner password grant - this one is not recommended by the specs but in my case since user must provide credentials to Authorization Service anyway and I will be hosting every project I can't see any problem.
Don't bother with OAuth and implement authorization mechanism using ASP.NET Core Identity + bearer token authentication.
Any ideas or recommendations highly apprecieated.
I use the JwtBearer package, wire it up in your Startup.cs Configure method like
.UseJwtBearerAuthentication(new JwtBearerOptions
{
AutomaticAuthenticate = true,
AutomaticChallenge = true,
TokenValidationParameters = new TokenValidationParameters
{
IssuerSigningKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(Configuration["AppSettings:AuthConfig:SecretKey"])),
ValidateIssuer = true,
ValidIssuer = Configuration["AppSettings:AuthConfig:Issuer"],
ValidateAudience = true,
ValidAudience = Configuration["AppSettings:AuthConfig:Audience"],
ValidateLifetime = true,
}
})
and my login action on my User controller looks like
[HttpPost]
public string Post([FromBody]LoginRequest request)
{
var contact = dbContext.Contacts.Where(c => c.Active && c.Email == request.Email).Select(c => new { c.Id, c.PasswordHash }).SingleOrDefault();
if (contact == null || !Security.PasswordHash.ValidatePassword(request.Password, contact.PasswordHash))
{
return string.Empty;
}
var signingKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(appSettings.AuthConfig.SecretKey));
var now = DateTime.UtcNow;
var claims = new Claim[]
{
new Claim(JwtRegisteredClaimNames.Sub, contact.Id.ToString()),
new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
new Claim(JwtRegisteredClaimNames.Iat, DateTimeOffset.Now.ToUnixTimeSeconds().ToString(), ClaimValueTypes.Integer64)
};
var jwt = new JwtSecurityToken(
issuer: appSettings.AuthConfig.Issuer,
audience: appSettings.AuthConfig.Audience,
claims: claims,
notBefore: now,
expires: now.AddDays(30),
signingCredentials: new SigningCredentials(signingKey, SecurityAlgorithms.HmacSha256));
jwt.Payload.Add("roles", dbContext.ContactRoles.Where(cr => cr.ContactId == contact.Id).Select(ur => ur.Role.Name).ToArray());
return new JwtSecurityTokenHandler().WriteToken(jwt);
}
I use a JWT package for Angular on the client, there may be something similar for React.
I am upgrading a project from .NET 4.6 to .NET Core. It is an ASP.NET MVC website with a WebAPI that uses EntityFramework. When the a (MVC or WebAPI) Controller fires up the DbContext, there is code that needs to identity the user as a ClaimsIdentity to inspect their claims. In previous .NET, this was most reliably available on Thread.CurrentPrincipal like this:
ClaimsIdentity identity = System.Threading.Thread.CurrentPrincipal.Identity as ClaimsIdentity;
IIRC, this was the safest way to do it since you could be coming from different contexts - WebAPI or ASP.NET MVC.
In the .NET core solution, I have tried to Dependency Inject an IHttpContextAccessor into the constructor, but the User on HttpContext is not authorized and has no claims
ClaimsIdentity identity = httpContext.HttpContext.User.Identity;
// identity.IsAuthenticated == false. identity.Claims is empty.
Security is wired up in Startup.cs:
services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme).
AddCookie(options =>
{
options.LoginPath = "/Login";
options.Cookie.HttpOnly = true;
}).
AddJwtBearer(options =>
{
options.RequireHttpsMetadata = false;
options.SaveToken = true;
var key = Configuration["Tokens:Key"];
options.TokenValidationParameters = new TokenValidationParameters()
{
ValidIssuer = Configuration["Tokens:Issuer"],
ValidAudience = Configuration["Tokens:Issuer"],
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(key))
};
});
The user logins on a /Login MVC view page, which logs in via Cookies and also generates a Bearer token in another request that is saved on the client. After all this the user is redirected to the homepage.
Cookie Login:
await HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, new ClaimsPrincipal(identity), new AuthenticationProperties() { IsPersistent = bIsPersistent });
Token Generation (called from ajax, saved to localstorage before redirection)
var secretKey = Configuration["Tokens:Key"];
var signingKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(secretKey));
var creds = new SigningCredentials(signingKey, SecurityAlgorithms.HmacSha256 );
var expires = DateTime.Now.AddHours(8);
var token = new JwtSecurityToken(
_config["Tokens:Issuer"],
_config["Tokens:Issuer"],
oAuthIdentity.Claims,
expires: expires,
signingCredentials: creds
);
ret = Ok(new { token = new JwtSecurityTokenHandler().WriteToken(token) });
After landing on the homepage, an ajax call is made to the WebApi with the bearer token (I pulled the bearer token out of the http request and verified the signature on jwt.io), and the webapi causes the DbContext to be instantiated, and this is where the identity is not valid.
It's as if the Identity is not properly marshalled over to the DbContext -
How to I get the correct User or Identity in the DbContext?
Additionally, at the point I need it is in the DbContext construction, which I don't have alot of control over with the Dependency Injection. But I need to get this info basically from a default constructor or lazy load it somehow.
With your setup, you have two authentications setup. So, in your ConfigureServices function in Startup class, you need to use something like the following:
services.AddAuthentication().AddCookie().AddJwtBearer();
Don't forget to specify a default authentication. For instance, if you want the authentication to be cookies by default, you can use this:
services.AddAuthentication("Cookies").AddCookie().AddJwtBearer();
Or to keep the code safer,
services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme).AddCookie().AddJwtBearer();
In your startup class, in the Configure function, don't forget to add
app.UseAuthentication();
When authenticating within a controller, you will need to use the scheme name along with the [Authorize] if you are not using the default scheme.
[Authorize(AuthenticationSchemes = "")]
I'm trying to setup integrated OWIN WS-Federation (ADFS) authentication in a new MVC 5 project in Visual Studio 2013. WsFederation in Startup.Auth is configured as follows:
app.UseWsFederationAuthentication(wtrealm: "MyRealm",
metadataAddress: "https://myADFSInstanceHost/FederationMetadata/2007-06/FederationMetadata.xml");
Federation button at login page works fine. ADFS login page is achievable, i can log in there.
Required cookies seems to being set properly. At least there is passed .AspNet.ExternalCookie cookie.
But when callback to mvc app is performed, in ExternalLoginCallback controller AuthenticationManager.GetExternalLoginInfoAsync() returns always null.
I know this is an extremely old post, but I've been working on this issue for a week and this is the ONLY resource I've found that provided any sort of help.
The comments on the original post provided exactly what I needed. In order for GetExternalLoginInfo to work, a claim of type NameIdentifier must be present. I was able to mock one of these in Startup.Auth.cs using the following code:
app.UserWsFederationAuthentication(
new WsFederationAuthenticationOptions
{
Wtrealm = realm, //defined earlier
MetadataAddress = adfsMetadata, //also defined earlier
Notifications = new WsFederationAuthenticationNotifications()
{
SecurityTokenValidated = notification =>
{
ClaimsIdentity identity = notification.AuthenticationTicket.Identity;
//loop through all the claims returned (this should return everything set up in ADFS)
foreach (var claim in notification.AuthenticationTicket.Identity.Claims)
{
if (claim.Type == ClaimTypes.Upn) //or whatever claim type you want to use as your name identifier
{
//This line will add a duplicate claim, giving it the specified type. This NEEDS TO BE `NameIdentifier`
identity.AddClaim(new Claim(ClaimTypes.NameIdentifier, claim.Value));
}
}
return Task.FromResult(0);
}
}
});
I have created a new ASP.NET MVC application with .NET 4.5. I have successfully set up authentication with an STS. The authentication flow is working fine and I am able to get the ClaimsIdentity, containing the desired claims, on Thread.CurrentPrincipal.
Now I need the bootstrap token to secure the calls to my service layer. I have set the saveBootstrapContext to true on the identityConfiguration element.
<system.identityModel>
<identityConfiguration saveBootstrapContext="true">
However, the BootstrapContext property on the ClaimsIdentity is always null.
var identity = Thread.CurrentPrincipal.Identity as ClaimsIdentity;
var context = identity.BootstrapContext; // context is always null
Am I missing anything here? This was supposed to be straightforward :(
Solved it by these:
<system.identityModel>
<identityConfiguration saveBootstrapContext="true" />
</system.identityModel>
Also need to set TokenValidationParameters.SaveSigninToken, which is distinct from JwtBearerOptions.SaveTokens:
app.UseWindowsAzureActiveDirectoryBearerAuthentication(
new WindowsAzureActiveDirectoryBearerAuthenticationOptions {
Tenant = ConfigurationManager.AppSettings["ida:Tenant"],
TokenValidationParameters = new TokenValidationParameters {
SaveSigninToken = true,
ValidAudience = ConfigurationManager.AppSettings["ida:Audience"]
}
}
);
I ran into this problem when hosting in IIS Express. It turns out that the issue was my browser - I had not closed all of my browser windows or cleared cookies, so the SessionSecurityToken was not being recreated with the new setting, even though the server had been restarted (the existing FedAuth cookie was still being sent from the browser).
Once I forced a re-authentication by closing all browser windows, restarting the browser and performing my request again, the BootstrapContext was present.
If you're using a message handler to manually validate the token using the JwtSecurityTokenHandler to extract a claims principal and attach that to the current Thread, as described here in Using the JWT handler for Implementing “Poor Man”’s Delegation/ActAs, when you're validating the token using JwtSecurityTokenHandler.ValidateToken(), one of the settings on TokenValidationParameters is
SaveBootstrapContext, setting that true does the trick.
I'm using Microsoft.AspNetCore.Authentication.OpenIdConnect, Version=5.0.4.0, and the setting is this:
.AddOpenIdConnect(o =>
{
// . . .
o.TokenValidationParameters.SaveSigninToken = true;
})