我有一个ASP.Net 4.5.2 MVC5 WebApi 5.2.3应用程序,它通常通过OWIN管道使用OAuth / Jwt安全性。现在,我有一个外部服务Web挂钩,通过POST调用我的一个WebApi控制器。此webhook服务仅支持基于Https的基本身份验证。这很好,如果我只能让我的过滤器(或其他)工作。
我的过滤器基于一个很好的example by Rick Strahl然而,当我在我的ApiController Action上面添加这个类然后我的[MyBasicAuthFilter]时,我得到的是一条服务器错误500消息{{Message“:”An错误已经发生。“}。
当我从POST调用中删除“Authorization:Basic dXNlcasdfasfdsfasd =”标题时,代码会输入我的新Filter。哦,太好了 :-[。因此,pipleline中较早的内容并不喜欢此标头存在的事实。我读了一下后怀疑是IIS设置。但是在尝试通过我的Web.Config胁迫Azure App Service IIS并立即阻止对我网站的所有访问之后,我想我会来这里寻求一些提示。
思想/提示?
答案 0 :(得分:0)
好的,这是关于这里发生了什么的独家新闻。现有的JsonWebTokenValidationHandler(消息处理程序)只是在寻找一个" Bearer"标题中的标记。如果出现任何其他令牌,那么它会将其标记为潜在攻击并返回HttpStatus 500.如果头部中根本没有令牌,那么它将返回挑战HttpStatus 401.无论如何,我的简约BasicAuth要求的最佳解决方案(在JWT令牌之上)是我的JsonWebTokenValidationHandler.cs的以下(完整)内容。这现在处理Bearer(JWT)令牌和Basic Auth令牌。欢迎评论。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using System.Web;
public class JsonWebTokenValidationHandler : DelegatingHandler
{
public string SymmetricKey { get; set; } // A0 client secret
public string Audience { get; set; } // A0 client ID
public string Issuer { get; set; } // A0 our A0 domain
private static bool TryRetrieveToken(HttpRequestMessage request, out string token)
{
token = null;
IEnumerable<string> authzHeaders;
if (!request.Headers.TryGetValues("Authorization", out authzHeaders) || authzHeaders.Count() > 1)
{
// Fail if no Authorization header or more than one Authorization headers
// are found in the HTTP request
return false;
}
// Remove the bearer token scheme prefix and return the rest as ACS token
var bearerToken = authzHeaders.ElementAt(0);
token = bearerToken.StartsWith("Bearer ") ? bearerToken.Substring(7) : bearerToken;
return true;
}
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
string token;
HttpResponseMessage errorResponse = null;
if (TryRetrieveToken(request, out token))
{
try
{
// ++
// Added BasicAuth to our JWT Auth
// If it is a BasicAuth token, then check it first and bypass JWT validation
// See Asp.Net WebApi security book for infos on this.
//
if (token.Contains("Basic"))
{
var authHeader = Encoding.Default.GetString(Convert.FromBase64String(token.Substring(6)));
// find first : as password allows for :
int idx = authHeader.IndexOf(':');
if (idx < 0)
return null;
string username = authHeader.Substring(0, idx);
string password = authHeader.Substring(idx + 1);
// Check the user's validity and reuse the JWT challenge 401 exception if not valid.
if (!ValidateBasicAuthUser(username, password))
{
throw new JsonWebToken.TokenValidationException(
$"Username or password missmatch for username: {username}");
}
// If OK, then let them in and continue
var identity = new BasicAuthenticationIdentity(username, password);
var principal = new GenericPrincipal(identity, null);
Thread.CurrentPrincipal = principal;
if (HttpContext.Current != null)
{
HttpContext.Current.User = Thread.CurrentPrincipal;
}
}
else
{
// --
// Handle JWT Tokens here or return server error 500 if it is not a valid token.
var secret = this.SymmetricKey.Replace('-', '+').Replace('_', '/');
Thread.CurrentPrincipal = JsonWebToken.ValidateToken(
token,
secret,
audience: this.Audience,
checkExpiration: true,
issuer: this.Issuer);
if (HttpContext.Current != null)
{
HttpContext.Current.User = Thread.CurrentPrincipal;
}
}
}
catch (JWT.SignatureVerificationException ex)
{
errorResponse = request.CreateErrorResponse(HttpStatusCode.Unauthorized, ex);
}
catch (JsonWebToken.TokenValidationException ex)
{
errorResponse = request.CreateErrorResponse(HttpStatusCode.Unauthorized, ex);
}
catch (Exception ex)
{
errorResponse = request.CreateErrorResponse(HttpStatusCode.InternalServerError, ex);
}
}
return errorResponse != null ?
Task.FromResult(errorResponse) :
base.SendAsync(request, cancellationToken);
}
/// <summary>
/// rht: Check our BasicAuth passwords e.g. from Cb WebHook
/// Usage: http://weblog.west-wind.com/posts/2013/Apr/18/A-WebAPI-Basic-Authentication-Authorization-Filter
/// </summary>
/// <param name="username"></param>
/// <param name="password"></param>
/// <returns></returns>
private bool ValidateBasicAuthUser(string username, string password)
{
if (string.IsNullOrEmpty(username) || string.IsNullOrEmpty(password))
return false;
var ok = false;
//
// Our valid usernames and passwords
//
switch (username)
{
case "your user 1 here":
{
if (password == "your password here") ok = true;
}
break;
case "your user 2 here or from DB, whatever":
{
if (password == "pwd") ok = true;
}
break;
}
return ok;
}
} // cl
//
// See: http://weblog.west-wind.com/posts/2013/Apr/18/A-WebAPI-Basic-Authentication-Authorization-Filter
// And Asp.Net WebApi Security book.
public class BasicAuthenticationIdentity : GenericIdentity
{
public BasicAuthenticationIdentity(string name, string password)
: base(name, "Basic")
{
this.Password = password;
}
/// <summary>
/// Basic Auth Password for custom authentication
/// </summary>
public string Password { get; set; }
}