Decrypt Bearer Token in Web API - c#

Is there a way to read/decrypt a bearer token in the web api project?
My web api is also hosting SignalR hubs which are called from the browser via websocket.
Unlike my normal api calls I cannot add the authorization header here. Though I can send the token in the query string and read this in the SignalR hub.
By default the token is resolved by owin into a claims identity. What I need is to do this manually. How would I do that?
OAuthAuthorizationServerOptions serverOptions = new OAuthAuthorizationServerOptions()
{
AllowInsecureHttp = true,
TokenEndpointPath = new PathString("/token"),
AccessTokenExpireTimeSpan = TimeSpan.FromDays(Config.TokenLifetime),
Provider = new AuthProvider()
};
// Token Generation
app.UseStageMarker(PipelineStage.Authenticate); // wait for authenticate stage, so we get the windows principle for use with ntlm authentication
app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions());
app.UseOAuthAuthorizationServer(serverOptions);

I assume that in Startup.cs you have a code similar to this:
var oAuthOpt = new OAuthBearerAuthenticationOptions
{
Provider = new OAuthTokenProvider(
req => req.Query.Get("bearer_token"),
req => req.Query.Get("access_token"),
req => req.Query.Get("refresh_token"),
req => req.Query.Get("token"),
req => req.Headers.Get("X-Token"))
};
app.UseOAuthBearerAuthentication(OAuthOpt);
app.UseOAuthAuthorizationServer(new OAuthAuthorizationServerOptions
{
AllowInsecureHttp = true,
TokenEndpointPath = new PathString(settings.TokenEndpointBasePath),
AccessTokenExpireTimeSpan = Util.AccessTokenExpireTimeSpan,
Provider = new AuthorizationServerProvider(new AuthenticationService()),
});
What you have to do is to replace oAuthOpt with a public static field in Startup.cs and than use it when you need to unprotect your bearer tokens.
For SignalR i'm creating an Authorization attribute where i take that oAuthOpt and use it decode tokens.
This is how I do it:
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = false, AllowMultiple = false)]
public sealed class AuthorizeHubAttribute : AuthorizeAttribute
{
public override bool AuthorizeHubConnection (HubDescriptor hubDescriptor, IRequest request)
{
var token = request.QueryString["Authorization"];
var ticket = Startup.OAuthOpt.AccessTokenFormat.Unprotect(token);
if ( ticket != null && ticket.Identity != null && ticket.Identity.IsAuthenticated )
{
request.Environment["server.User"] = new ClaimsPrincipal(ticket.Identity);
return true;
}
else
return false;
}
public override bool AuthorizeHubMethodInvocation (IHubIncomingInvokerContext hubIncomingInvokerContext, bool appliesToMethod)
{
var connectionId = hubIncomingInvokerContext.Hub.Context.ConnectionId;
var environment = hubIncomingInvokerContext.Hub.Context.Request.Environment;
var principal = environment["server.User"] as ClaimsPrincipal;
if ( principal != null && principal.Identity != null && principal.Identity.IsAuthenticated )
{
hubIncomingInvokerContext.Hub.Context = new HubCallerContext(new Microsoft.AspNet.SignalR.Owin.ServerRequest(environment), connectionId);
return true;
}
else
return false;
}
}
var ticket = Startup.OAuthOpt.AccessTokenFormat.Unprotect(token);
That line is the connection with Startup.cs

Related

How to mock "aud" claim in c# Moq

I am trying to write unit tests for authentication logic implemented using Azure AD client credentials flow using MOQ.
The first test case is to check that if the "Audience" is valid. I am trying to mock claim to set up the "aud" or "appId" claims using ClaimTypes but not able to find anything like ClaimTypes.Aud
var identity = new ClaimsIdentity(new Claim[] {
new Claim(ClaimTypes.Name, "Sahil")
});
var mockPrincipal = new Mock<ClaimsPrincipal>(identity);
mockPrincipal.Setup(x => x.Identity).Returns(identity);
mockPrincipal.Setup(x => x.IsInRole(It.IsAny<string>())).Returns(true);
How can I set up the "aud" and "appId" claims in C#
OR
Just setup mockPrincipal so that when it tries to check if "aud" is valid it returs false.
I am trying to write unit tests for the below code.
public void Authenticate(JwtBearerOptions options)
{
_configuration.Bind("AzureAD", options);
options.TokenValidationParameters.ValidateAudience = true;
options.TokenValidationParameters.ValidateIssuerSigningKey = true;
options.TokenValidationParameters.ValidateIssuer = true;
options.Events ??= new JwtBearerEvents();
var existingHandlers = options.Events.OnTokenValidated;
options.Events.OnTokenValidated = async context =>
{
string appId = GetAppIdFromToken(context);
bool isAllowed = await CheckAppIdIsAllowedAsync(context, appId);
if (isAllowed)
{
_logger.LogInformation($"[{nameof(Authenticate)}] AppId in allow list");
}
else
{
_logger.LogError($"[{nameof(Authenticate)}] AppId {appId} not in allowed list");
}
await Task.CompletedTask.ConfigureAwait(false);
};
options.Events.OnTokenValidated += existingHandlers;
}
private string GetAppIdFromToken(TokenValidatedContext context)
{
string appId = context.Principal.Claims.FirstOrDefault(x => x.Type == "appid" || x.Type == "azp")?.Value;
return appId;
}
private async Task<bool> CheckAppIdIsAllowedAsync(TokenValidatedContext context, string appId)
{
IEnumerable<string> AllowedApps = _configuration.GetSection("AllowedAppPrincipals").Get<string[]>();
var FoundAppId = AllowedApps.FirstOrDefault(a => a == appId);
if (FoundAppId == null)
{
context.Response.StatusCode = (int)HttpStatusCode.Forbidden;
context.Response.ContentType = "application/json";
const string message = "{\"error\" : \"Unacceptable app principal\"}";
byte[] arr = Encoding.ASCII.GetBytes(message);
await context.Response.BodyWriter.WriteAsync(arr);
context.Fail(message);
return false;
}
return true;
}
How to mock aud and appId claims with Moq?
I tried to reproduce how to get audience invalid in my environment.
It usually happens when the issuer endpoint is different or scope is not given correctly or different scope than what is intended is mentioned.
https://login.microsoftonline.com/xx/oauth2/v2.0/token
Here i gave scope for api other than microsoft graph.
But next tep i am calling graph endpoint and so i am getting invalid audience error .
https://graph.microsoft.com/v1.0/users/xxx
To check for mocking test , you can consider below point as direct claims for "aud" audience in c# couldn't be obtained AFAIK.
Aud claim is Application ID URI or GUID Identifies the intended
audience of the token. In v2.0 tokens, audience must be client ID
of the API whereas in v1.0 tokens, it can be the client ID or the
resource URI used in the request.
One way to validate it is to check following way with issuer/audience
You can give custom values according to the authorization endpoint
Code:
string AUDIENCE = "<GUID of your Audience according to the app>";
string TENANT = "<GUID of your Tenant>";
private static async Task<SecurityToken> validateJwtTokenAsync(string token)
{
// URL based on your AAD-TenantId
var stsDiscoveryEndpoint = String.Format(CultureInfo.InvariantCulture, "https://login.microsoftonline.com/{0}/.well-known/openid-configuration", TENANT);
//To Get tenant information
var configManager = new ConfigurationManager<OpenIdConnectConfiguration>(stsDiscoveryEndpoint)
// Get Config from AAD:
var config = await configManager.GetConfigurationAsync();
// Validate token:
var tokenHandler = new JwtSecurityTokenHandler();
var validationParameters = new TokenValidationParameters
{
ValidAudience = AUDIENCE,
ValidIssuer = config.Issuer,
IssuerSigningTokens = config.SigningTokens,
CertificateValidator = X509CertificateValidator.ChainTrust,
};
var validatedToken = (SecurityToken)new JwtSecurityToken();
tokenHandler.ValidateToken(token, validationParameters, out validatedToken);
return validatedToken;
}
Or
var TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuerSigningKey = true,
IssuerSigningKey = key,
ValidateIssuer = true,
ValidateAudience = true,
ValidateLifetime = false,
....
ValidIssuer = configuration["JwtAuthentication:Issuer"],
ValidAudience = configuration["JwtAuthentication:Audience"]
};
So from validation parameters, you can get if that we that audience was valid or not, it majorly occurs when issuer is different from what we expected or when scopes are not correct.
You can try get those validate as claims to check for mocking
Snippent below taken from TokenValidationParameters.AudienceValidator, System.IdentityModel.Tokens C# (CSharp) Code Examples - HotExamples
public virtual ClaimsPrincipal ValidateToken(string securityToken, TokenValidationParameters validationParameters, out SecurityToken
validatedToken)
{
if (string.IsNullOrWhiteSpace(securityToken))
{
throw new ArgumentNullException("securityToken");
}
if (validationParameters == null)
{
throw new ArgumentNullException("validationParameters");
}
if (validationParameters.ValidateAudience)
{
if (validationParameters.AudienceValidator != null)
{
if
(!validationParameters.AudienceValidator(jwt.Audiences, jwt,
validationParameters))
{
throw new SecurityTokenInvalidAudienceException(string.Format(CultureInfo.InvariantCulture,
ErrorMessages.IDX10231, jwt.ToString()));
}
}
else
{
this.ValidateAudience(jwt.Audiences, jwt,
validationParameters);
}
}
ClaimsIdentity identity = this.CreateClaimsIdentity(jwt, issuer,
validationParameters);
if (validationParameters.SaveSigninToken)
{
identity.BootstrapContext = new
BootstrapContext(securityToken);
}
validatedToken = jwt;
return new ClaimsPrincipal(identity);
}
Also check Reference :c# - How to mock ConfigurationManager.AppSettings with moq - Stack Overflow

AccessToken from Azure ADB2C in MVC5 application

We are working on a MVC5 web application, that uses OpenIdConnect to authenticate to Azure AD B2C. When a user has authenticated, we would like to be able to acquire accesstokens from Azure AD B2C, in order to use them our API.
This is our Startup.cs-equivalent code:
protected override void ProcessCore(IdentityProvidersArgs args)
{
Assert.ArgumentNotNull(args, nameof(args));
List<B2CConfig> ssoSettings = _ssoConfigurationRepository.GetAllSettings();
foreach (var config in ssoSettings)
{
args.App.UseOpenIdConnectAuthentication(CreateOptionsFromSiteConfig(config));
}
}
private OpenIdConnectAuthenticationOptions CreateOptionsFromSiteConfig(B2CConfig config)
{
OpenIdConnectAuthenticationOptions options = new OpenIdConnectAuthenticationOptions();
options.MetadataAddress = string.Format(_aadInstance, _tenant, config.Policy);
options.AuthenticationType = config.Policy;
options.AuthenticationMode = AuthenticationMode.Passive;
options.RedirectUri = config.AzureReplyUri;
options.PostLogoutRedirectUri = config.LogoutRedirectUri;
options.TokenValidationParameters = new TokenValidationParameters
{
NameClaimType = "emails"
};
var identityProvider = GetIdentityProvider();
options.Notifications = new OpenIdConnectAuthenticationNotifications()
{
AuthenticationFailed = AuthenticationFailed,
RedirectToIdentityProvider = notification =>
{
return Task.FromResult(notification.ProtocolMessage.UiLocales = config.UiLocale ?? string.Empty);
},
SecurityTokenValidated = notification =>
{
notification.AuthenticationTicket.Identity.AddClaim(new Claim("idp", "azureadb2c"));
// transform all claims
ClaimsIdentity identity = notification.AuthenticationTicket.Identity;
notification.AuthenticationTicket.Identity.ApplyClaimsTransformations(new TransformationContext(FederatedAuthenticationConfiguration, identityProvider));
return Task.CompletedTask;
}
};
options.ClientId = config.ClientId;
options.Scope = "openid";
options.ResponseType = "id_token";
return options;
}
private Task AuthenticationFailed(AuthenticationFailedNotification<OpenIdConnectMessage, OpenIdConnectAuthenticationOptions> notification)
{
notification.HandleResponse();
// Handle the error code that Azure AD B2C throws when trying to reset a password from the login page
// because password reset is not supported by a "sign-up or sign-in policy"
if (notification.ProtocolMessage.ErrorDescription != null && notification.ProtocolMessage.ErrorDescription.Contains("AADB2C90118"))
{
SsoLogger.Warn("User triggered reset password");
notification.Response.Redirect(SsoConfiguration.Routes.ResetPassword);
}
else if (notification.Exception.Message == "access_denied")
{
notification.Response.Redirect("/");
}
else
{
SsoLogger.Warn("AuthenticationFailed", notification.Exception);
notification.Response.Redirect(SsoConfiguration.Routes.LoginError);
}
return Task.FromResult(0);
}
In Asp.Net core it seems like you would call GetTokenAsync on the HttpContext, but that extensionmethod is not available in .NET 4.72.
Can anyone help figuring out, how to retrieve an accesstoken from AzureAD B2C, that can be used in the calls to our WebApi? Or can I just store the accesstoken I get from the SecurityTokenValidated event and use that for all API requests?
This is a possible solution: Is it safe to store an access_token in a user claim for authorization?
Notifications = new OpenIdConnectAuthenticationNotifications
{
SecurityTokenValidated = notification =>
{
var identity = notification.AuthenticationTicket.Identity;
identity.AddClaim(claim: new Claim(type: "auth_token", value:
notification.ProtocolMessage.AccessToken));
return Task.CompletedTask;
}
}
If anyone has a better approach I will gladly accept another answer.

Manually generate IdentityServer4 reference token and save to PersistedGrants table

I have learnt IdentityServer4 for a week and successfully implemented a simple authentication flow with ResourceOwnedPassword flow.
Now, I'm implementing Google authentication with IdentityServer4 by following this tutorial
This is what I am doing:
Startup.cs
public void ConfigureServices(IServiceCollection services)
{
//...
const string connectionString = #"Data Source=.\SQLEXPRESS;database=IdentityServer4.Quickstart.EntityFramework-2.0.0;trusted_connection=yes;";
var migrationsAssembly = typeof(Startup).GetTypeInfo().Assembly.GetName().Name;
services.AddIdentityServer()
.AddDeveloperSigningCredential()
.AddProfileService<IdentityServerProfileService>()
.AddResourceOwnerValidator<IdentityResourceOwnerPasswordValidator>()
// this adds the config data from DB (clients, resources)
.AddConfigurationStore(options =>
{
options.ConfigureDbContext = builder =>
{
builder.UseSqlServer(connectionString,
sql => sql.MigrationsAssembly(migrationsAssembly));
};
})
// this adds the operational data from DB (codes, tokens, consents)
.AddOperationalStore(options =>
{
options.ConfigureDbContext = builder =>
builder.UseSqlServer(connectionString,
sql => sql.MigrationsAssembly(migrationsAssembly));
// this enables automatic token cleanup. this is optional.
options.EnableTokenCleanup = true;
options.TokenCleanupInterval = 30;
});
// Add jwt validation.
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddIdentityServerAuthentication(options =>
{
// base-address of your identityserver
options.Authority = "https://localhost:44386";
options.ClaimsIssuer = "https://localhost:44386";
// name of the API resource
options.ApiName = "api1";
options.ApiSecret = "secret";
options.RequireHttpsMetadata = false;
options.SupportedTokens = SupportedTokens.Reference;
});
//...
}
** Google controller (Which is for handling returned token from Google **
public class GLoginController : Controller
{
#region Properties
private readonly IPersistedGrantStore _persistedGrantStore;
private readonly IUserFactory _userFactory;
private readonly IBaseTimeService _baseTimeService;
private readonly ITokenCreationService _tokenCreationService;
private readonly IReferenceTokenStore _referenceTokenStore;
private readonly IBaseEncryptionService _baseEncryptionService;
#endregion
#region Constructor
public GLoginController(IPersistedGrantStore persistedGrantStore,
IBaseTimeService basetimeService,
ITokenCreationService tokenCreationService,
IReferenceTokenStore referenceTokenStore,
IBaseEncryptionService baseEncryptionService,
IUserFactory userFactory)
{
_persistedGrantStore = persistedGrantStore;
_baseTimeService = basetimeService;
_userFactory = userFactory;
_tokenCreationService = tokenCreationService;
_referenceTokenStore = referenceTokenStore;
_baseEncryptionService = baseEncryptionService;
}
#endregion
#region Methods
[HttpGet("login")]
[AllowAnonymous]
public IActionResult Login()
{
var authenticationProperties = new AuthenticationProperties
{
RedirectUri = "/api/google/handle-external-login"
};
return Challenge(authenticationProperties, "Google");
}
[HttpGet("handle-external-login")]
//[Authorize("ExternalCookie")]
[AllowAnonymous]
public async Task<IActionResult> HandleExternalLogin()
{
//Here we can retrieve the claims
var authenticationResult = await HttpContext.AuthenticateAsync(IdentityServerConstants.ExternalCookieAuthenticationScheme);
var principal = authenticationResult.Principal;
var emailAddress = principal.FindFirst(ClaimTypes.Email)?.Value;
if (string.IsNullOrEmpty(emailAddress))
return NotFound(new ApiMessageViewModel("Email is not found"));
// Find user by using username.
var loadUserConditions = new LoadUserModel();
loadUserConditions.Usernames = new HashSet<string> { emailAddress };
loadUserConditions.Pagination = new PaginationValueObject(1, 1);
// Find users asynchronously.
var loadUsersResult = await _userFactory.FindUsersAsync(loadUserConditions);
var user = loadUsersResult.FirstOrDefault();
// User is not defined.
if (user == null)
{
user = new User(Guid.NewGuid(), emailAddress);
user.Email = emailAddress;
user.HashedPassword = _baseEncryptionService.Md5Hash("abcde12345-");
user.JoinedTime = _baseTimeService.DateTimeUtcToUnix(DateTime.UtcNow);
user.Kind = UserKinds.Google;
user.Status = UserStatuses.Active;
//await _userFactory.AddUserAsync(user);
}
else
{
// User is not google account.
if (user.Kind != UserKinds.Google)
return Forbid("User is not allowed to access system.");
}
var token = new Token(IdentityServerConstants.TokenTypes.IdentityToken);
var userCredential = new UserCredential(user);
token.Claims = userCredential.GetClaims();
token.AccessTokenType = AccessTokenType.Reference;
token.ClientId = "ro.client";
token.CreationTime = DateTime.UtcNow;
token.Audiences = new[] {"api1"};
token.Lifetime = 3600;
return Ok();
}
#endregion
}
Everything is fine, I can get claims returned from Google OAuth2, find users in database using Google email address and register them if they dont have any acounts.
My question is: How can I use Google OAuth2 claims that I receive in HandleExternalLogin method to generate a Reference Token, save it to PersistedGrants table and return to client.
This means when user access https://localhost:44386/api/google/login, after being redirected to Google consent screen, they can receive access_token, refresh_token that has been generated by IdentityServer4.
Thank you,
In IdentityServer the kind (jwt of reference) of the token is
configurable for each client (application), requested the token.
AccessTokenType.Reference is valid for TokenTypes.AccessToken not
TokenTypes.IdentityToken as in your snippet.
In general it would be simpler to follow the original quickstart and then extend the generic code up to your needs. What I can see now in the snippet above is just your specific stuff and not the default part, responsible for creating the IdSrv session and redirecting back to the client.
If you still like to create a token manually:
inject ITokenService into your controller.
fix the error I mentioned above: TokenTypes.AccessToken instead of TokenTypes.IdentityToken
call var tokenHandle = await TokenService.CreateAccessTokenAsync(token);
tokenHandle is a key in PersistedGrantStore

How to add custom headers to an open id connect authentication request in OWIN middleware

I have a system where I have an MVC website calling a web api. I have used OAUTH and OPENID Connect for my authentication/authorization. I have setup an identity server in another web api project using Thinktecture's IdentityServer3. In the MVC project I am doing the redirect to the identity server in the OWIN Startup class. This is all pretty standard stuff and is working fine.
I have now been asked to put the web api and the identity server behind Azure API Management. This also, is fine as all I need to do from my MVC project is add my subscription key from API management as a header ("Ocp-Apim-Subscription-Key") to any request to the web api. So far so good.
The problem is I now need to add this header to any requests to the identity server and I can't work out how, other than writing my own middleware. My Startup class looks like this:
public class Startup
{
public void Configuration(IAppBuilder app)
{
DependencyResolver.SetResolver(new SimpleInjectorDependencyResolver(IocHelper.GetContainer()));
JwtSecurityTokenHandler.InboundClaimTypeMap = new Dictionary<string, string>();
app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = "Cookies"
});
app.UseOpenIdConnectAuthentication(new OpenIdConnectAuthenticationOptions
{
ClientId = ConfigurationHelper.GetClientId(),
Authority = ConfigurationHelper.GetSecurityTokenServiceUrl(),
RedirectUri = ConfigurationHelper.GetPortalHomePageUrl(),
PostLogoutRedirectUri = ConfigurationHelper.GetPortalHomePageUrl(),
ResponseType = "code id_token",
Scope = "openid profile public_api",
TokenValidationParameters = new TokenValidationParameters
{
NameClaimType = "name",
RoleClaimType = "role"
},
SignInAsAuthenticationType = "Cookies",
Notifications = new OpenIdConnectAuthenticationNotifications
{
AuthorizationCodeReceived = async n =>
{
// use the code to get the access and refresh token
var tokenClient = new TokenClient(ConfigurationHelper.GetTokenEndpointUrl(), ConfigurationHelper.GetClientId(), ConfigurationHelper.GetClientSecret());
var tokenResponse = await tokenClient.RequestAuthorizationCodeAsync(n.Code, n.RedirectUri);
if (tokenResponse.IsError)
{
throw new Exception(tokenResponse.Error);
}
// use the access token to retrieve claims from userinfo
var userInfoClient = new UserInfoClient(ConfigurationHelper.GetUserInfoUrl());
var userInfoResponse = await userInfoClient.GetAsync(tokenResponse.AccessToken);
if (userInfoResponse.IsError)
{
throw new Exception(userInfoResponse.Error);
}
// create new identity
var id = new ClaimsIdentity(n.AuthenticationTicket.Identity.AuthenticationType);
foreach (var c in userInfoResponse.Claims)
{
id.AddClaim(new Claim(c.Type, c.Value));
}
id.AddClaim(new Claim("access_token", tokenResponse.AccessToken));
id.AddClaim(new Claim("expires_at", DateTime.Now.AddSeconds(tokenResponse.ExpiresIn * 2).ToLocalTime().ToString(CultureInfo.InvariantCulture)));
id.AddClaim(new Claim("id_token", n.ProtocolMessage.IdToken));
id.AddClaim(new Claim("sid", n.AuthenticationTicket.Identity.FindFirst("sid").Value));
var claimsIdentity = new ClaimsIdentity(id.Claims, n.AuthenticationTicket.Identity.AuthenticationType, "name", "role");
//claimsIdentity.IsAuthenticated = true;
n.AuthenticationTicket = new AuthenticationTicket(claimsIdentity, n.AuthenticationTicket.Properties);
},
RedirectToIdentityProvider = n =>
{
// if signing out, add the id_token_hint
if (n.ProtocolMessage.RequestType != OpenIdConnectRequestType.LogoutRequest)
{
return Task.FromResult(0);
}
var idTokenHint = n.OwinContext.Authentication.User.FindFirst("id_token");
if (idTokenHint != null)
{
n.ProtocolMessage.IdTokenHint = idTokenHint.Value;
}
// DOESN'T WORK
n.OwinContext.Request.Headers.Append("Ocp-Apim-Subscription-Key", "MY KEY GOES HERE");
// ALSO DOESN'T WORK
n.Request.Headers.Append("Ocp-Apim-Subscription-Key", "MY KEY GOES HERE");
return Task.FromResult(0);
}
}
});
}
}
Is there a way to hi-jack the request to the identity server and add my own header in there?

Using Thinktecture.IdentityModel lib using UseBasicAuthentication with Webapi and OWIN the Identity in my controllers has no claims

I am using Thinktecture.IdentityModel and trying to use the Owin.BasicAuthentication lib with the UseBasicAuthentication with Webapi and OWIN. The Identity in my controllers has no claims and shows not authenticated.
I setup the owin config with this in Startup.Auth.cs
app.SetDefaultSignInAsAuthenticationType("Basic");
//app.Use(typeof (BasicAuthentication), new[] {_container.Resolve<UserAccountService>()});
app.UseBasicAuthentication(new BasicAuthenticationOptions("realm", ValidationFunction)
{
AuthenticationType = "Basic",
AuthenticationMode = AuthenticationMode.Active
});
var oauthServerConfig = new OAuthAuthorizationServerOptions
{
AllowInsecureHttp = true,
Provider = new MembershipRebootProvider(_container.Resolve<UserAccountService>()),
TokenEndpointPath = new PathString("/token")
};
app.UseOAuthAuthorizationServer(oauthServerConfig);
var oauthConfig = new OAuthBearerAuthenticationOptions
{
AuthenticationMode = Microsoft.Owin.Security.AuthenticationMode.Active,
AuthenticationType = "Bearer"
};
app.UseOAuthBearerAuthentication(oauthConfig);
private static Task<IEnumerable<Claim>> ValidationFunction(string userName, string password)
{
IEnumerable<Claim> claims = null;
UserAccount user;
string tenant = "";
if (userName.Contains("\\"))
{
var parts = userName.Split('\\');
tenant = parts[0];
userName = parts[1];
}
else
{
throw new Exception("Cannot determine tenant and username.");
}
var userAccountService = _container.Resolve<UserAccountService>();
if (userAccountService.Authenticate(tenant, userName, password, out user))
{
claims = user.GetAllClaims();
}
return Task.FromResult(claims);
}
the claims are returned from membership reboot as expected.
But when I view it in my controller method there are no claims and it says not authenticated..
var identity = (ClaimsPrincipal)Thread.CurrentPrincipal;
What am i missing?
I did have the suppress SuppressDefaultHostAuthentication in the config but when checking this I noticed I did not have a filter for "Basic" only Oauth BearerToken. I added that and now it works!
config.SuppressDefaultHostAuthentication();
config.Filters.Add(new HostAuthenticationFilter(OAuthDefaults.AuthenticationType));
config.Filters.Add(new HostAuthenticationFilter("Basic"));

Categories

Resources