当安全的REST端点已经存在时,如何验证SOAP服务中的令牌

本文关键字:验证 服务 令牌 何验证 SOAP 端点 REST 安全 存在 | 更新日期: 2023-09-27 18:03:35

我有一点Frankenstien服务,因为它有SOAP和REST的端点,它们由相同的代码库托管在相同的URL上。我正在使用客户机凭证授予流来成功地保护REST端点,但希望使用相同的流程来保护SOAP调用。cs初始化身份服务器承载令牌身份验证,如下所示:

JwtSecurityTokenHandler.InboundClaimTypeMap = new Dictionary<string, string>();
app.UseIdentityServerBearerTokenAuthentication(new IdentityServerBearerTokenAuthenticationOptions
{
    Authority = ConfigurationManager.AppSettings["IdentityServerUrl"],
    RequiredScopes = new[] { ConfigurationManager.AppSettings["IdentityServerScopes"] }
});
对于REST端点,我添加了一个
[Authorize]

代码装饰和一切工作。对于SOAP端,我重新利用了密码字段,并通过它发送了令牌,可以像这样解码:

string sPassword = request.Authentication.Password;
if (sPassword.Contains("."))
{
    "'nAccess Token (decoded):".ConsoleGreen();
    var parts = sPassword.Split('.');
    var header = parts[0];
    var claims = parts[1];
    Console.WriteLine(JObject.Parse(Encoding.UTF8.GetString(Base64Url.Decode(header))));
    Console.WriteLine(JObject.Parse(Encoding.UTF8.GetString(Base64Url.Decode(claims))));
}

我可以看到声明,但这并没有验证令牌。从这里开始,我拼凑了一个ValidateToken方法,该方法会抛出关于签名验证失败的异常。无法解析SecurityKeyIdentifier。我相当确定所有内容都已由IdentityServer3证书签名,但我在尝试创建证书时遇到了问题。我的KeyStore中没有任何证书,我想要一个不需要在KeyStore中插入证书的解决方案。下面是尝试:

public static bool VerifyToken(string token)
{
    const string thumbPrint = "6bf8e136eb36d4a56ea05c7ae4b9a45b63bf975d"; // correct thumbprint of certificate
    var cert = X509CertificateHelper.FindByThumbprint(StoreName.My, StoreLocation.LocalMachine, thumbPrint).First();
    var validationParameters = new TokenValidationParameters()
    {
        //IssuerSigningToken = new BinarySecretSecurityToken(_key),
        IssuerSigningToken = new X509SecurityToken(cert),
        ValidAudience = "https://securityeli.twcable.com/core/resources",
        ValidIssuer = "https://securityeli.twcable.com/core",
        ValidateLifetime = true,
        ValidateAudience = true,
        ValidateIssuer = true
        //ValidateIssuerSigningKey = true
    };
    var tokenHandler = new JwtSecurityTokenHandler();
    SecurityToken validatedToken = null;
    try
    {
        tokenHandler.ValidateToken(token, validationParameters, out validatedToken);
    }
    catch (Exception ex)
    {
        throw new Exception(ex.Message);
    }
    //... manual validations return false if anything untoward is discovered
    return validatedToken != null;
}
public class X509CertificateHelper
{
    public static IEnumerable<X509Certificate2> FindByThumbprint(StoreName storeName, StoreLocation storeLocation, string thumbprint)
    {
        var store = new X509Store(storeName, storeLocation);
        store.Open(OpenFlags.ReadOnly);
        var certificates = store.Certificates.Find(X509FindType.FindByThumbprint, thumbprint, false);
        foreach (var certificate in certificates)
        {
            yield return certificate;
        }
        store.Close();
    }
}

当前进程不能工作,因为我的密钥存储库中没有密钥。BinarySecretSecurityToken失败,因为我不知道密钥长度?

我还将回到房子的REST端,它使用授权标记验证承载令牌,因此我应该可以访问证书,但不知道如何将其从应用程序中取出。我可以在启动中看到它通过了我无法访问的IAPPBuilder应用程序。

两个问题是如何创建证书来验证c#中IdentityServer3中创建的令牌?我能取回那张证书吗?

当安全的REST端点已经存在时,如何验证SOAP服务中的令牌

在尝试了多个路径后,我终于找到了一些有效的方法,我将尝试捕获相关部分,以防其他人试图做同样的事情。

首先,我将传入的令牌分成几个部分:

    var parts = sPassword.Split('.');
    var header = parts[0];
    var claims = parts[1];
    var token = new JwtSecurityToken(sPassword);

然后设置一些变量并调用自定义VerifyToken方法:

    CustomResponse customResponse = null;
    SecurityToken validatedToken = null;
    ClaimsPrincipal claimsPrincipal = null;
    if (VerifyToken(sPassword, ref customResponse, ref validatedToken, ref claimsPrincipal))
    {
        // Process SOAP request after authentication
    }
    else
        return customResponse; // token wasn't authenticated, and not authorized message was set in the VerifyToken method

VerifyToken方法看起来像这样:

    public static bool VerifyToken(string token, ref CustomResponse customResponse, ref SecurityToken validatedToken, ref ClaimsPrincipal claimsPrincipal)
    {
            // This was the biggest challenge in finding the cert that is used to validate the token
        var certString = "Found in the CallbackController.cs in the IdentityServer3.Samples repository"
        var cert = new X509Certificate2(Convert.FromBase64String(certString));
            // Setting what you'd like the authorization to validate.
        var validationParameters = new TokenValidationParameters()
        {
            IssuerSigningToken = new X509SecurityToken(cert),
            ValidAudience = ConfigurationManager.AppSettings["IdentityServerUrl"] + "/resources",
            ValidIssuer = ConfigurationManager.AppSettings["IdentityServerUrl"],
            ValidateLifetime = true,
            ValidateAudience = true,
            ValidateIssuer = true,
            ValidateIssuerSigningKey = true
        };
        var tokenHandler = new JwtSecurityTokenHandler();
        try
        {
            claimsPrincipal = tokenHandler.ValidateToken(token, validationParameters, out validatedToken);
        }
        catch (SecurityTokenValidationException e)
        {
            //HttpContext.Current.Response.StatusCode = 401;
            //statusCode = HttpStatusCode.Unauthorized;
            customResponse = new CustomResponse();
            customResponse.ServiceReturnStatus = new ServiceReturnStatus();
            customResponse.ServiceReturnStatus.ReturnCode = -401;
            customResponse.ServiceReturnStatus.ReturnMessage = "Unauthorized";
        }
        catch (Exception e)
        {
            //HttpContext.Current.Response.StatusCode = 403;
            //statusCode = HttpStatusCode.InternalServerError;
            customResponse = new CustomResponse();
            customResponse.ServiceReturnStatus = new ServiceReturnStatus();
            customResponse.ServiceReturnStatus.ReturnCode = -403;
            customResponse.ServiceReturnStatus.ReturnMessage = "Internal Server Error";
        }
        //... manual validations return false if anything untoward is discovered
        return validatedToken != null;
    }
    private string GetClaimFromPrincipal(ClaimsPrincipal principal, string claimType)
    {
        var uidClaim = principal != null && principal.Claims != null ? principal.Claims.FirstOrDefault(s => s.Type == claimType) : null;
        return uidClaim != null ? uidClaim.Value : null;
    }

我还添加了一个GetClaimFromPrincipal,您可以使用它从主体中获取索赔。

就是这样,它看起来并不那么复杂,但我确实花了很多时间来尝试和错误地让它工作。我仍然想要一个使用Owin Startup信息来验证/授权令牌的选项因为我所做的基本上是加载我在Startup。cs中加载的所有信息,如下所示:

    app.UseIdentityServerBearerTokenAuthentication(new IdentityServerBearerTokenAuthenticationOptions
    {
        Authority = ConfigurationManager.AppSettings["IdentityServerUrl"],
        RequiredScopes = new[] { ConfigurationManager.AppSettings["IdentityServerScopes"] }
    });