从 SOAP 请求主体节点读取 ClientCredentials 并根据自定义验证器对其进行验证?

发布于 2024-11-13 09:14:04 字数 4303 浏览 13 评论 0原文

我有一个方法 GetColors,它接受 GetColorIdsRQ 作为参数并返回 GetColorIdsRSGetColorIdsRQ 是 SOAP 请求,GetColorIdsRS 是 SOAP 响应。以下是每个方法的实现细节:

GetColorIdsRQ:

[DataContract]
public class GetColorIdsRQ
{
    [DataMember(Name="UserCredentials",Order=0,IsRequired=true)]
    public UserCredentials UserCredentials { get; set; }
}

UserCredentials:

[DataContract(Name="UserCredentials")]
public class UserCredentials
{
    [DataMember(Name="Username",Order=0,IsRequired=true)]
    public string UserName { get; set; }
    [DataMember(Name="Password",Order=1,IsRequired=true)]
    public string Password { get; set; }
}

GetColorIdsRS:

[DataContract]
public class GetColorIdsRS
{
    [DataMember(Name = "ColorsIds", IsRequired = true, Order = 0)]
    public List<Color> ColorIds { get; set; }
}

Color:

[DataContract(Name="Color")]
public class Color    
{
   [DataMember(Name="Code",IsRequired=true,Order=0)]
   public string Code { get; set; }
   [DataMember(Name="Name",IsRequired=true,Order=1)]
   public string Name { get; set; }  
}

这是该方法在接口中的声明方式:

[OperationContract(Name = "GetColorIds")]
GetColorIdsRS GetColorsIds(GetColorIdsRQ req);

这是 GetColorIds 的实现:

public GetColorIdsRS GetColors(GetColorIdsRQ req)
{
    GetColorIdsRS getColorIdsRS = new GetColorIdsRS();
    List<Color> colorIds = new List<Color>();

    req.UserCredentials.UserName = "test";
    req.UserCredentials.Password = "test";

    //Validate Username and Password

    DataTable dtColorIds = Data.GetDataTable("GetColors");

    foreach (DataRow item in dtColorIds.Rows)
    {
        colorIds.Add(new Color { Name = item["Name"].ToString(), 
                                 Code = item["ColorId"].ToString() });
    }

    getColorIdsRS.ColorIds = colorIds;

    return getColorIdsRS;
}

当我从 WCF 测试客户端调用 GetColors 时,请求正文为:

<s:Body>
    <GetColors xmlns="http://test.com/2011/05">
      <req xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
       <UserCredentials>
         <Username>test</Username>
         <Password>test2</Password>
       </UserCredentials>
     </req>
   </GetColors>
 </s:Body>

上述问题是我想使用 CustomUserNameValidatorUsernamePassword 节点。我不确定如何让 CustomUserNameValidator 识别 GetColorIdsRQ 用户名和密码节点,以便它可以对其进行验证。如果您注意到上面的 GetColors 方法,我正在设置:

req.UserCredentials.UserName = "test";
req.UserCredentials.Password = "test";

但这显然没有得到验证。以下是我的 CustomUserNamePasswordValidator 的实现:

public class CustomUserNameValidator : UserNamePasswordValidator
{
    public override void Validate(string userName, string password)
    {
        // check if the user is not test
        if (userName != "test" || password != "test")
            throw new FaultException("Username and Password Failed");
    }
}

因此,基本上如果我通过:

req.UserCredentials.UserName = "test";
req.UserCredentials.Password = "test2";

CustomUserNameValidator 应该抛出FaultException。

另请注意,在 GetColors 方法中,我有一条注释“//验证用户名和密码”,我知道我可以这样做:

CustomUserNameValidator val = new CustomUserNameValidator();
val.Validate(req.UserCredentials.UserName,req.UserCredentials.Password)

上面将调用 Validate 方法,但我知道它应该是自动的,然后我会在每一个方法中都做到这一点。

调用 CustomUserNameValidator 的唯一方法是在代理代码中设置 ClientCredentials 吗?例如:

proxy.ClientCredentials.UserName.UserName = "test;
proxy.ClientCredentials.UserName.Password = "test;

上述内容会导致调用 Validate 方法,但如果我无法执行上述操作并且设置了用户名和密码作为 Request 对象的属性,则不会调用 Validate,因此我的另一个选择是在每个需要它的操作中使用我自己的 Validate 方法。如果 ClientCredentials 失败,则不会调用操作,但在我的例子中,我需要调用一个操作,然后让它返回一个 SOAP 响应,并带有一个错误节点,其中包含“无效的用户名和/或密码”之类的内容,而不是抛出异常一个错误异常。

根据上述内容,在我的情况下最好避免使用 CustomUserNamePasswordValidator 吗?

如果无法通过代理的客户端凭据设置用户名和密码,而是通过肥皂请求的正文发送,那么处理此问题的方法似乎是在操作基础上处理验证,并且不会这会影响安全设置(例如,是否有必要设置 clientCredentialType="Username")

I have a method GetColors which takes a GetColorIdsRQ as a parameter and returns a GetColorIdsRS. GetColorIdsRQ is the SOAP Request and GetColorIdsRS is the SOAP Resposne. Here are the implementation details of each one:

GetColorIdsRQ:

[DataContract]
public class GetColorIdsRQ
{
    [DataMember(Name="UserCredentials",Order=0,IsRequired=true)]
    public UserCredentials UserCredentials { get; set; }
}

UserCredentials:

[DataContract(Name="UserCredentials")]
public class UserCredentials
{
    [DataMember(Name="Username",Order=0,IsRequired=true)]
    public string UserName { get; set; }
    [DataMember(Name="Password",Order=1,IsRequired=true)]
    public string Password { get; set; }
}

GetColorIdsRS:

[DataContract]
public class GetColorIdsRS
{
    [DataMember(Name = "ColorsIds", IsRequired = true, Order = 0)]
    public List<Color> ColorIds { get; set; }
}

Color:

[DataContract(Name="Color")]
public class Color    
{
   [DataMember(Name="Code",IsRequired=true,Order=0)]
   public string Code { get; set; }
   [DataMember(Name="Name",IsRequired=true,Order=1)]
   public string Name { get; set; }  
}

This is how the method is declaration in the interface:

[OperationContract(Name = "GetColorIds")]
GetColorIdsRS GetColorsIds(GetColorIdsRQ req);

This is the implementation of GetColorIds:

public GetColorIdsRS GetColors(GetColorIdsRQ req)
{
    GetColorIdsRS getColorIdsRS = new GetColorIdsRS();
    List<Color> colorIds = new List<Color>();

    req.UserCredentials.UserName = "test";
    req.UserCredentials.Password = "test";

    //Validate Username and Password

    DataTable dtColorIds = Data.GetDataTable("GetColors");

    foreach (DataRow item in dtColorIds.Rows)
    {
        colorIds.Add(new Color { Name = item["Name"].ToString(), 
                                 Code = item["ColorId"].ToString() });
    }

    getColorIdsRS.ColorIds = colorIds;

    return getColorIdsRS;
}

When I invoke GetColors from the WCF Test client, the Request Body is:

<s:Body>
    <GetColors xmlns="http://test.com/2011/05">
      <req xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
       <UserCredentials>
         <Username>test</Username>
         <Password>test2</Password>
       </UserCredentials>
     </req>
   </GetColors>
 </s:Body>

The problem with the above is that I want to use the Username and Password nodes for the CustomUserNameValidator. I am not sure how to get the CustomUserNameValidator to recoginize GetColorIdsRQ Username and Password nodes so it can validate against that. If you notice above in the GetColors method, I am setting:

req.UserCredentials.UserName = "test";
req.UserCredentials.Password = "test";

but this doesn't get Validated obviously. Here is the implementation of my CustomUserNamePasswordValidator:

public class CustomUserNameValidator : UserNamePasswordValidator
{
    public override void Validate(string userName, string password)
    {
        // check if the user is not test
        if (userName != "test" || password != "test")
            throw new FaultException("Username and Password Failed");
    }
}

So essentially if I pass:

req.UserCredentials.UserName = "test";
req.UserCredentials.Password = "test2";

The CustomUserNameValidator should throw the FaultException.

Notice also in the GetColors method, I have a comment "//Validate Username and Password", I know I can do:

CustomUserNameValidator val = new CustomUserNameValidator();
val.Validate(req.UserCredentials.UserName,req.UserCredentials.Password)

and the above would call the Validate method, but I was made aware that it should be automatic and then I would have to do this in every single method.

Is it true that the only way for the CustomUserNameValidator to get called is to set the ClientCredentials in proxy code such as:

proxy.ClientCredentials.UserName.UserName = "test;
proxy.ClientCredentials.UserName.Password = "test;

The above would cause the Validate method to be called, but if I am unable to do the above and I set the Username and Password as properties of the Request object, then Validate won't be called, so my other option is to just have my own Validate method within each operation that requires it. An operation will not be called if the ClientCredentials fail, but in my case, I need an operation to call and then for it to return an SOAP Response with an error node with something like "Invalid Username and/or Password" instead of a throwing a FaultException.

Based on the above, is it best to avoid using the CustomUserNamePasswordValidator in my case?

In the event that the username and password can't be set through the proxy's client credentials, but is rather sent through the body of the soap request, then it appears that the way to handle this is to handle validation on an operational basis and does this affect the security settings (for example, is there a point to have a clientCredentialType="Username")

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

痕至 2024-11-20 09:14:04

这是不可能的,除非您深入研究 WCF 安全管道并实现自定义安全令牌(即使这样您也可以发现这是不可能的)以及与此实现相关的所有内容 - 它是 大量工作

为什么不使用标准的用户名身份验证?

编辑:

如果您想在消息正文的自定义元素中传递凭据(并且您不会更改安全管道),则验证由您决定 - 它不会被路由到用户名验证器。您必须在操作中执行此操作,或者可以构建自定义消息检查器(实现 IMessageInspector )并使用自定义端点行为 (IEndpointBehavior ) 包装它以集中验证。

That is not possible unless you dive deeply into WCF security pipeline and implement custom security token (even then you can find that it is not possible) and all the stuff related to this implementation - it is a lot of work.

Why don't you use standard UserName authentication?

Edit:

If you want to pass credentials in custom element in message body (and you will not change security pipeline), the validation is up to you - it will not be routed to user name validator. You must do it either in operation or you can build custom message inspector (implement IMessageInspector) and wrap it with custom endpoint behavior (IEndpointBehavior) to have validation centralized.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文