January 2009 - Posts

According to the WS-Trust specification, a service consumer has a way to negotiate or ask for specific claims to the STS. Those claims (or some of them) will be generally used by  the service implementation running on the relying party.

They are negotiated through an "claims" element in the RST message,

<wst:RequestSecurityToken xmlns:wst="...">

        <wst:TokenType>...</wst:TokenType>

        <wst:RequestType>...</wst:RequestType>

        ...

        <wsp:AppliesTo>...</wsp:AppliesTo>

        <wst:Claims Dialect="...">...</wst:Claims>

        <wst:Entropy>

              <wst:BinarySecret>...</wst:BinarySecret>

         </wst:Entropy>

        <wst:Lifetime>

            <wsu:Created>...</wsu:Created>

            <wsu:Expires>...</wsu:Expires>

        </wst:Lifetime>

</wst:RequestSecurityToken>

The "wst:claims" is an optional element for requesting a specific set of claims. Typically, this element contains required and/or optional claim information identified in a service's policy.

Based on these facts, we can elaborate some possible scenarios for claims negotiation between these three parties.

1. No negotiation at all

The STS might just ignore these claims requirements in the RST message and always returns a fixed claim set according to the consumer identity, or the service might not express what claims it expects at all. This scenario might be suitable for a local STS in small-sized or medium-sized organizations, where the IT department has a complete control over the client applications and services that interact with that STS. This kind of solution is easier to implement, and quite rigid too, a change in the claims required by the service will also require changes in the STS implementation. As you see, this solution does not scale at all for a high number of applications or relying party services.

Many of the STS examples you will find today are implemented like this.

2. Negotiation based on the AppliesTo header.

This solution present a subtle difference with the one discussed before, the claims vary according the relying party that will make use of them. The STS ignores the claims requirements in the RST messages and returns a claim set based on the received AppliesTo header. An existing agreement must exist between the STS and the relying party, which will include in addition to the key for encrypting the tokens, a number of expected claims.  Again, easy to implement, difficult to scale up.

3. Manual negotiation based on the "Claims" header.

In this scenario, the consumer sends the expected claims in the "claims" header and the STS makes use of them for generating the resulting token. However, the negotiation of those claims between the consumer and the relying party is manual, a previous agreement must exist, the service does not express those requirements through metadata. This means that the claims are hard-coded during development in the client configuration.  If the service requires additional claims, only the client configuration will have to be changed, the STS does not have to be touched at all.

If you are implementing a custom STS with the latest Microsoft Geneva bits, there is a property "Claims" in the RequestSecurityToken for getting access to these values.

protected override IClaimsIdentity GetOutputClaimsIdentity(IClaimsPrincipal principal, RequestSecurityToken request, Scope scope)

{

    IClaimsIdentity outputIdentity = new ClaimsIdentity();

 

    foreach (Claim claim in request.Claims)

    {

        //Do something...

 

        outputIdentity.Claims.Add(...);

    }

 

    return outputIdentity;

}

The client can specify those claims through configuration as well,

<wsFederationHttpBinding>

  <binding name="ServiceBinding">

    <security mode="Message">

      <message issuedTokenType="http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.1#SAMLV1.1" negotiateServiceCredential="false">

        <claimTypeRequirements>

          <add claimType ="http://schemas.microsoft.com/ws/2005/05/identity/claims/EmailAddress"/>

          <add claimType ="http://schemas.microsoft.com/ws/2005/05/identity/claims/GivenName"/>

          <add claimType ="http://schemas.microsoft.com/ws/2005/05/identity/claims/Surname" isOptional ="true"/>

        </claimTypeRequirements>

        <issuer></issuer>

      </message>

    </security>

  </binding>

</wsFederationHttpBinding>

Once they are added to the binding configuration, WCF will automatically include them as part of the RST message to the STS.

4. Automatic negotiation based on the "Claims" header.

This is by far the best solution we can find. The three parties automatically negotiates the claims at runtime,

I. The service exposes the claim requirements through metadata (WS-Policy)

II. The client acquires the service's policy and requirements using some mechanism that could be WS-MetatadaExchange.  Later,  the client includes some claim requirements into the RST message that will be send to the STS.

III. The STS extracts those requirements from the RST message, and then, it makes use of them for generating the resulting token.

The Cardspace identity selector on the consumer side works like this. It first detects what claims are needed by the Relying Party, and then, displays all the possible cards (From different Identity providers) that satisfy those requirements to the user.

Exposing the claim requirements on the relying party through WCF is equivalent to do it on the client side (same binding configuration),

<wsFederationHttpBinding>

  <binding name="ServiceBinding">

    <security mode="Message">

      <message issuedTokenType="http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.1#SAMLV1.1">

        <claimTypeRequirements>

          <add claimType ="http://schemas.microsoft.com/ws/2005/05/identity/claims/EmailAddress"/>

          <add claimType ="http://schemas.microsoft.com/ws/2005/05/identity/claims/GivenName"/>

          <add claimType ="http://schemas.microsoft.com/ws/2005/05/identity/claims/Surname" isOptional ="true"/>

        </claimTypeRequirements>

        <issuer></issuer>

      </message>

    </security>

  </binding>

</wsFederationHttpBinding>

Posted by cibrax | 1 comment(s)
Filed under: , ,

Keith Brown has just released a helper class (Based on an original implementation made by Dominick Baier) with very useful methods for mixing Http and Https in a regular asp.net application. Before jumping in this post, make sure to read his post (And Dominick's) to understand all the problems you may have to deal with when implementing a partial SSL website.

Running a partial SSL website in ASP.NET MVC is not much different, however, in MVC, we can leverage the existing and powerful routing mechanism to implement similar features.

Switching to SSL through an ASP.NET Module

This module  basically inspects the URL and does a redirect based on some configuration where you specify routes that should be SSL protected.

public void ProcessRequest(HttpContext context)

{

    if(Authentication.IsSslRequired() && context.Request.HttpMethod.Equals("get", StringComparison.OrdinalIgnoreCase))

    {

        var data = RouteTable.Routes.GetRouteData(new HttpContextWrapper(context));

        if (data != null)

        {

            if (!context.Request.IsSecureConnection)

            {

                if(data.DataTokens["isSecure"] != null && (bool)data.DataTokens["isSecure"])

                {

                    //Do redirect to https

                    var secureUrl = context.Request.Url.ToString().ToSslUrl();

                    context.Response.Redirect(secureUrl, true);

                }

            }

            else

            {

                if (data.DataTokens["isSecure"] == null || !((bool)data.DataTokens["isSecure"]))

                {

                    //Do redirect to http

                    var unsecureUrl = context.Request.Url.ToString().ToUnsecureUrl();

                    context.Response.Redirect(unsecureUrl, true);

                }

            }

        }

    }

}

As you can see in the code above, the module checks whether the page should be ssl protected using a custom data token (IsSecure) that was previously configured for the route, and afterwards, it redirects the request according to that setting. For instance, if the route requires to be the secure (IsSecure = true), and the request was actually made through http, the module will redirect the request to https.

The absolute URLs are built using some extensions methods (ToSslUrl and ToUnsecureUrl) that I will show later in this post.

Authentication.IsSslRequired is just an configuration setting that we can use to skip all these checks during development.

public class Authentication

{

    public static bool IsSslRequired()

    {

        var setting = ConfigurationManager.AppSettings["RequireSSL"];

        if (setting != null)

        {

            return bool.Parse(setting);

        }

 

        return false;

    }

}

 

<appSettings>

  <add key="RequireSSL" value="True"/>

</appSettings>

The code for setting the custom data token in the MVC route looks as follow,

routes.MapRoute(

    "MyAccount/PasswordChange",

    "MyAccount/PasswordChange",

    new { controller = "Accounts", action = "PasswordChange" }

).DataTokens = new RouteValueDictionary(new { isSecure = true });

 

Extension methods for generating absolute URLs

As I showed before in the ASP.NET Module, two extensions methods were used to generate absolute URLs. I just based their implementation on some code originally written by Troy Goode in this post.

/// <summary>

/// Provides helper extensions for turning strings into fully-qualified and SSL-enabled Urls.

/// </summary>

public static class UrlStringExtensions

{

    /// <summary>

    /// Takes a relative or absolute url and returns the fully-qualified url path.

    /// </summary>

    /// <param name="text">The url to make fully-qualified. Ex: Home/About</param>

    /// <returns>The absolute url plus protocol, server, & port. Ex: http://localhost:1234/Home/About</returns>

    public static string ToFullyQualifiedUrl( this string text )

    {

        var oldUrl = text;

        var oldUrlArray = ( oldUrl.Contains( "?" ) ? oldUrl.Split( '?' ) : new[]{ oldUrl, "" } );

 

        var requestUri = HttpContext.Current.Request.Url;

        var localPathAndQuery = requestUri.LocalPath + requestUri.Query;

        var urlBase = requestUri.AbsoluteUri.Substring( 0, requestUri.AbsoluteUri.Length - localPathAndQuery.Length );

 

        var newUrl = VirtualPathUtility.ToAbsolute( oldUrlArray[0] );

        if( !string.IsNullOrEmpty( oldUrlArray[1] ) )

            newUrl += "?" + oldUrlArray[1];

 

        return urlBase + newUrl;

    }

 

    /// <summary>

    /// Looks for Html links in the passed string and turns each relative or absolute url and returns the fully-qualified url path.

    /// </summary>

    /// <param name="text">The url to make fully-qualified. Ex: <a href="Home/About">Blah</a></param>

    /// <returns>The absolute url plus protocol, server, & port. Ex: <a href="http://localhost:1234/Home/About">Blah</a></returns>

    public static string ToFullyQualifiedLink( this string text )

    {

        var regex = new Regex(

            "(?<Before><a.*href=\")(?!http)(?<Url>.*?)(?<After>\".+>)",

            RegexOptions.Multiline | RegexOptions.IgnoreCase

            );

 

        return regex.Replace( text, ( Match m ) =>

                                    m.Groups["Before"].Value +

                                    ToFullyQualifiedUrl( m.Groups["Url"].Value ) +

                                    m.Groups["After"].Value

            );

    }

 

    /// <summary>

    /// Takes a relative or absolute url and returns the fully-qualified url path using the Https protocol.

    /// </summary>

    /// <param name="text">The url to make fully-qualified. Ex: Home/About</param>

    /// <returns>The absolute url plus server, & port using the Https protocol. Ex: https://localhost:1234/Home/About</returns>

    public static string ToSslUrl( this string text )

    {

        if (IsSslRequired())

        {

            string absoluteUrl = null;

            if (text.StartsWith("http://", StringComparison.OrdinalIgnoreCase) || text.StartsWith("https://", StringComparison.OrdinalIgnoreCase))

                absoluteUrl = text;

            else

                absoluteUrl = ToFullyQualifiedUrl(text);

 

            return absoluteUrl.Replace("http:", "https:");

        }

        else

        {

            return text;

        }

    }

 

    /// <summary>

    /// Takes a relative or absolute url and returns the fully-qualified url path using the Http protocol.

    /// </summary>

    /// <param name="text">The url to make fully-qualified. Ex: Home/About</param>

    /// <returns>The absolute url plus server, & port using the Http protocol. Ex: http://localhost:1234/Home/About</returns>

    public static string ToUnsecureUrl(this string text)

    {

        string absoluteUrl = null;

        if (text.StartsWith("http://", StringComparison.OrdinalIgnoreCase) || text.StartsWith("https://", StringComparison.OrdinalIgnoreCase))

            absoluteUrl = text;

        else

            absoluteUrl = ToFullyQualifiedUrl(text);

 

        return absoluteUrl.Replace("https:", "http:");

    }

 

    /// <summary>

    /// Looks for Html links in the passed string and turns each relative or absolute url into a fully-qualified url path using the Https protocol.

    /// </summary>

    /// <param name="text">The url to make fully-qualified. Ex: <a href="Home/About">Blah</a></param>

    /// <returns>The absolute url plus server, & port using the Https protocol. Ex: <a href="https://localhost:1234/Home/About">Blah</a></returns>

    public static string ToSslLink( this string text )

    {

        if (IsSslRequired())

        {

            return ToFullyQualifiedLink(text).Replace("http:", "https:");

        }

        else

        {

            return ToFullyQualifiedLink(text);

        }

    }

 

    private static bool IsSslRequired()

    {

        return Authentication.IsSslRequired();

    }

}


They can be used from a view as well to generate links with complete Urls,

<a href='<% =Url.Action("PasswordChange", "Accounts").ToSslUrl() %>'>Change your password</a>

Gettting an absolute URL within a controller

For some scenarios, we might need to redirect the user from a secure route to a regular route or viceversa within a controller. In those cases, we should have a way to generate a complete URL from a controller method and used it later with a RedirectResult (This is also useful when you want to include a link to a web page in an email sent by your website).

For instance, it would be very helpful to have something like this,

return new RedirectResult(this.FullActionUrl<MyController>(c => c.SecureMethod(), "https"));

Where "FullActionUrl" is an extension method for the Controller class. In addition to the controller method we want to use to get the absolute route ("SecureMethod"), we can also specify the scheme to be used with that route.

The code for doing that is shown bellow (They are part of the .NETfx project, http://code.google.com/p/netfx/)

/// <summary>

/// Returns the full URL for performing an invocation to an action based

/// on an expression representing an invocation to a controller method

/// that may include arguments.

/// </summary>

/// <typeparam name="T">Type of the controller to call to. Can be omitted as it can be inferred from the action type.</typeparam>

/// <param name="controller">The controller performing the call.</param>

/// <param name="action">The action containing the call.</param>

public static string FullActionUrl<T>(this Controller controller, Expression<Action<T>> action, string scheme)

    where T : Controller

{

    string host = controller.HttpContext.Request.Url.Authority;

    string virtualPath = ActionUrl(controller, action);

 

    return string.Format("{0}://{1}{2}", scheme, host, virtualPath);

}

 

/// <summary>

/// Returns the URL for performing an invokation to an action based

/// on an expression representing an invocation to a controller method

/// that may include arguments.

/// </summary>

/// <typeparam name="T">Type of the controller to call to. Can be omitted as it can be inferred from the action type.</typeparam>

/// <param name="controller">The controller performing the call.</param>

/// <param name="action">The action containing the call.</param>

public static string ActionUrl<T>(this ControllerBase controller, Expression<Action<T>> action)

    where T : Controller

{

    var call = ControllerExpression.GetMethodCall<T>(action);

 

    string actionName = call.Method.Name;

    string controllerName = ControllerExpression.GetControllerName<T>();

 

    var values = LinkBuilder.BuildParameterValuesFromExpression(call);

    values.Add("action", actionName);

    values.Add("controller", controllerName);

 

    var vpd = RouteTable.Routes.GetVirtualPath(controller.ControllerContext, values);

    string target = null;

    if (vpd != null)

    {

        target = vpd.VirtualPath;

    }

 

    return target;

}

The complete code is available to download from here

Posted by cibrax | 1 comment(s)
Filed under: ,

The other day I came across this interesting article written by Subbu Allamaraju, where he discusses some of the aspects that drive the design of a pure and self-describing RESTful interface for a service (Or service contract in other words).

He points out three main pieces that every service contract should have:

1. An uniform interface. An uniform interface is probably one the aspects that we best know about REST, or we may heard often when a REST service is described. This refers to the fact that each service exposes the same interface, which is a good thing for eliminating ad hoc messages and focusing primarily on an standard API that defines pieces of information that can be retrieved and manipulated. Instead of adding special function calls or interfaces to the architecture, new services add new pieces of information can be manipulated using standard requests. For instance, in Http RESTful services, this point involves using standard http verbs, headers and status codes.

2. Resource representations based on media types. This is quite interesting, what he proposes is to use a more specialized "content-type" for any of the xml schemas that a service may return. He confirms that generic media types such as "application/xml" are not enough to distinguish resource representations. We might want to know if the resource represents an account or a customer without making any assumptions about the resource's URI. In those cases, content types like "application/vnd.bank.org.accounts+xml" or "application/vnd.bank.org.customers+xml" would be more helpful and still being valid according to the spec  "rfc3023, XML media types".

200 OK
Content-Type: application/vnd.bank.org.account+xml

<accounts xmlns="urn:org:bank:accounts">
    <account>
        <id>AZA12093</id>       
        <balance currency="USD">993.95</balance>
    </account>
</accounts>

3. Contextual links to resources. In addition to the resource representation, the client should also receive links representing what it can do next (Taking the form of a workflow). As Subbu concludes, this aspect decouples the client from the actual URIs of resources, and the client does not need to know the rest of the URIs until run-time.

200 OK
Content-Type: application/vnd.bank.org.account+xml;charset=UTF-8

<accounts xmlns="urn:org:bank:accounts">
    <account>
        <id>AZA12093</id>
        <link href="http://bank.org/account/AZA12093" rel="self"/>
        <link rel="
http://bank.org/rel/transfer edit"
              type="application/vnd.bank.org.transfer+xml"
              href="
http://bank.org/transfers"/>
        <link rel="
http://bank.org/rel/customer"
              type="application/vnd.bank.org.customer+xml"
              href="
http://bank.org/customer/7t676323a"/>
        <balance currency="USD">993.95</balance>
    </account>
    .....

As you can see in the example above, the account representation contains links to itself (Self link) and other resources. The operations that can be performed over those resources are expressed by the "rel" attribute.

Altough there is not built-in support in WCF to enforce these aspects automatically, it can be easily done in the service implementation using specific data contracts and the WebOperationContext. 

Setting up the content type before returning the service response:

public Account GetAccount(string id)

{

  WebOperationContext.Current.OutgoingResponse.ContentType = "application/vnd.bank.org.account+xml";

  return repository.Accounts.Where(a => a.Id == id).FirstOrDefault();

}

A link can be modeled as a regular data contract:

[DataContract(Name="link")]

public class Link

{

   [DataMember(Name="href")]

   public string Href { get; set; }

 

   [DataMember(Name = "rel")]

   public string Rel { get; set; }

 

   [DataMember(Name = "type")]

   public string Type { get; set; }

}

Read the article for more information.

Posted by cibrax | 2 comment(s)
More Posts