WP7 with Caliburn Micro - Securing screens - part 1

  This is going to be a series of posts about securing screens in a Windows Phone 7 Silverlight application. The Goal: Coming from .Net web applications, I was looking for a feature that will be similar to the authentication and authorization capabilities of Asp.Net with Forms Authentication. I want to be able to easily define a screen as secure and automatically show the login UI when needed without having extra code in each screen. If the entire app needs to be secured, I can just show a login screen as the first screen but when the user presses the back button from the home page I don’t want to go back to that screen. With MyMobilePortfolio, I used a popup for the login UI. the popup is opened from the home page of the app. In this solution I will take it one step further by having public and secure screens in the app. Caliburn Micro I’ve been using Caliburn Micro since I started developing WP7 apps and I love it. This framework is moving rapidly and some of the features I will use in this series of posts are in the latest checked in code but not in the latest release (at the time of writing). If something is missing, you should get the latest code and compile the Caliburn.Micro library yourself. Step 1 – Figure out if a screen requires authentication before navigating to that screen. There are two ways to accomplish this. Keep the list of secured screens in the applications configuration (a la asp.net) or add some definition to each screen if it’s secure. I’ve decided to take the second approach. I don't want to have some config file I need to update, the only advantage there would be if you wanted to quickly change a screen's secure setting without redeploying. That works in the web world but not in a mobile app.Since I’m using Caliburn Micro, I wanted to define a screen as secure in the view model and not in the view itself so I decided to create an interface called IRestricedAccess that I can check against before navigating to a screen. Caliburn Micro uses a FrameAdapter class to navigate, I’m going to inherit from that class and change the Navigate method to include some logic (if a ViewModel implements IRestrictedAccess show the login screen, if not, just continue the navigation). In the WP7AppBootstrapper class, I’ll replace the FrameAdapter instance with SecurableFrameAdapter. Because the Navigate method receives a uri, I have to use some conventions to figure out what the type of the view model is. This code was ‘borrowed’ from Caliburn Micro and simplified a bit to fit my own project. The attached project is a basic WP7 Caliburn Micro application. The Framework folder includes the SimpleContainer and PhoneContainer classes that come with CM samples, the WP7AppBootstrapper and the SecurableFrameAdapter.There are four screens linked from the main page screen, two public and two secure.  In the next post, I'll add the login UI WP7SecuredScreensPart1.zip (78.86 kb)

Windows Phone 7 and WCF REST – Authentication Solutions

I’ve been scouring the internets looking for a simple solution for authentication with WP7. I am using a simple WCF REST web service based on the template for .net 4.0 Here are the two solutions I ended up with: Solution 1 – Use the built in authentication service Add a new WCF service to your project, remove the code behind file and change the svc file to this:  <%@ ServiceHost Language="C#" Debug="true" Service="System.Web.ApplicationServices.AuthenticationService" %>

.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /white-space: pre;/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; } Add the forms authentication and membership configuration (just like any asp.net website) Now in the WP7 project, you can add a service reference, again, this part is very standard. To get this working, you need to use the cookie container on calls to both services. Instead of detailing this approach, I figured I’ll just link to Kevin Hoffman’s blog post Solution 2 – Use basic authentication This solution is a lot more restful. There’s no state saved on the server, no session and no cookies. I’ve decided to use RestSharpfor server calls from WP7. It’s very easy to ad basic authentication code on the client side when using RestSharp since the library has built in support for it using the HttpBasicAuthenticator. var request = new RestRequest("Orders");

          request.Method = Method.GET;

          request.RequestFormat = DataFormat.Json;

          var client = new RestClient(baseUrl);

          client.Authenticator = new HttpBasicAuthenticator(userName, password);

          client.ExecuteAsync(request, (response) =&gt;

          {

              if (response.StatusCode == HttpStatusCode.OK)

              {

                  //deal with the response

              }

          });

.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /white-space: pre;/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }What I like about RestSharp is being able to define my resource. To get authentication working, I just needed one line of additional code on the client side.

So far, I’m sending the basic auth base64 encoded header to the server, now I need to intercept it on the server side and authenticate the user. To do that, I added a class that inherits from ServiceAuthorizationManager, here’s the code:

public class BasicAuthorization : ServiceAuthorizationManager
{
    protected override bool CheckAccessCore(OperationContext operationContext)
    {
        string authtext = HttpContext.Current.Request.Headers[&quot;Authorization&quot;];
        //if (String.IsNullOrWhiteSpace(authtext))
            //return false;
        if (!String.IsNullOrWhiteSpace(authtext))
        {
            string[] decoded = DecodeFrom64(authtext.Replace(&quot;Basic &quot;, String.Empty)).Split(':');
            string username = decoded[0];
            string password = decoded[1];

            if (Membership.ValidateUser(username, password))
            {

                MembershipUser user = Membership.GetUser(username);
                GenericIdentity identity = new GenericIdentity(user.UserName);
                //RolePrincipal principal = new RolePrincipal(identity);
                GenericPrincipal principal = new GenericPrincipal(identity, &quot;UserRole&quot;.Split(','));
                System.Threading.Thread.CurrentPrincipal = principal;
                HttpContext.Current.User = principal;
                //return true;
            }
        }

        //always return true, we just want to get the identity set up so methods can support authorization
        return true;
    }

    /// &lt;summary&gt;
    /// The method to Decode your Base64 strings.
    /// &lt;/summary&gt;
    /// &lt;param name=&quot;encodedData&quot;&gt;The String containing the characters to decode.&lt;/param&gt;
    /// &lt;returns&gt;A String containing the results of decoding the specified sequence of bytes.&lt;/returns&gt;
    private static string DecodeFrom64(string encodedData)
    {
        byte[] encodedDataAsBytes = System.Convert.FromBase64String(encodedData);
        string returnValue = System.Text.Encoding.UTF8.GetString(encodedDataAsBytes);
        return returnValue;
    }
}

There’s nothing complicated here, I’m just decoding the base64 string from the header and using the membership functions to validate the user’s credentials and create an IPrincipal object which is then set as the current user. This will allow methods in the actual service to access the membership object in a standard way. That’s also the reason the method always returns true. I’m not interested in blocking access at this point, I’ll leave that up to individual methods. (If you wanted to secure the entire service for authenticated users, you could return the result of the ValidateUser call, I wanted to have a methods that can be called by anonymous users as well).

This sample doesn’t add the user’s actual roles, which will be easy to implement (just get the roles using the username and add to the principal)

The last step is to update the servicemodel configuration to use the BasicAuthorization class. Just find the default behavior for your REST service and add the ServiceAuthoization element.

<behavior name=""> <serviceMetadata httpGetEnabled="true"/> <serviceDebug includeExceptionDetailInFaults="true"/> <serviceAuthorization serviceAuthorizationManagerType="SampleWCFRESTService.BasicAuthorization, SampleWCFRESTService" /> </behavior>

.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /white-space: pre;/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }

Now checking “HttpContext.Current.User.Identity.IsAuthenticated” in any method in the web service will work.

 

The problem with basic authentication

The problem of course, is sending user credentials with every request. Since I don’t want to send all of the requests over SSL due to performance issues (and I usually don’t really have to) I need a better solution.

The standard solution for this problem is to make the first call over SSL to an “Authenticate” resource, create a token and send it back to the client. From that point on you can send the token with subsequent requests.

To add support for a token, you can add another ServiceAuthorizationManager or just update the logic to check if the Authorization header starts with Basic or CustomName. The encrypted token should include the username and password and you can add other elements to it (like expiration for example).

In my implementation, my Authentication resource andthe ServiceAuthotizationManager both use the same class to encrypt/decrypt the username and password and in that class I also check if the token has expired.

I decided to go with the second solution since it seems to be the standard way REST services are developed (sending user/pass and getting a token). I wouldn’t really want to deal with cookies and that solution might not be friendly to other platforms.

The SQL SiteMap Provider and trimming by roles (originally posted 2006-09-20)

This is a post from my old blog and since I'm about to delete it I've decided to move the post over here, enjoy...

For a while now I've been using the SqlSiteMapProvider from the Wicked Code article by Jeff Prosise. This provider works great but it was missing a few things, so I decided to improve it a bit.

One of the most common mistakes/confusions about sitemaps in ASP.Net 2.0 is that the Roles attribute in the sitemap will be used to trim these pages for users not in this role. From what I understand, in the providers that ship with ASP.Net 2.0, this attribute is actually used for showing this page links to this roles and not for hiding them from anyone not in those roles.

Another problem with the sitemap is that in order to trim the site navigation controls (TreeView and Menu or any control that uses the SiteMapDataSource) you must set authorization rules in the web.config files by using the <location> section or by having separate web.config files in different folders.

What I wanted to do is have the Roles set on a page in the sitemap control everything.

After looking around for a while, I found that the trimming solution is very simple and easy and it's actually just one override that's missing from the SqlSiteMapProvider.

IsAccessibleToUser is the method that needs to be overridden. This methods gets the HTTP context and the SiteMapNode of the current request. You can get the User object from the context and the Roles from the SiteMapNode and simply check if the user is in any of these roles using the IsInRole method.

Here's the code:

public override bool IsAccessibleToUser(HttpContext context, SiteMapNode node) { //If Security Trimming is not enabled return true if (!SecurityTrimmingEnabled) return true;

//If there are no roles defined for the page //return true or false depending on your authorization scheme (when true pages with //no roles are visible to all users, when false no user can access these pages) if (node.Roles == null node.Roles.Count == 0) return false;

//check each role, if the user is in any of the roles return true foreach (string role in node.Roles) { if (context.User.IsInRole(role) String.Equals(role, "*", StringComparison.InvariantCultureIgnoreCase)) return true; }

return false; }

After adding this code, pages that have roles the user is not in will not be visible in menus and treeviews but the user will still be able to access these pages with a direct URL. A simple check when the page loads using the SiteMap.CurrentNode.Roles and the User.IsInRole can helps us find out if the user should be able to see this page. I usually use a base class that all pages inherit from (and that inherits from System.Web.UI.Page), so I simply added the code to the OnLoad method of the base class. Here's the code: if (User.Identity.IsAuthenticated) { bool isUserAllowed = false; if (SiteMap.CurrentNode != null) { if (SiteMap.CurrentNode.Roles != null && SiteMap.CurrentNode.Roles.Count > 0) {

foreach (string role in SiteMap.CurrentNode.Roles) { if (context.User.IsInRole(role) String.Equals(role, "*", StringComparison.InvariantCultureIgnoreCase)) { isUserAllowed = true; break; } } } else { //no roles for this page, deny access to the page //if you want to allow access to pages without roles defined set to true isUserAllowed = false; } } if (!isUserAllowed) Response.Redirect("AccessDenied.aspx"); }

After adding these methods you no longer need the <authorization> tags in the web.config file. the data from the UsersInRoles and SiteMap tables will be used instead, allowing full control of page access rules from your application.