Securing the Controller - XSockets/XSockets.NET-4.0 GitHub Wiki

##Securing the Controller XSockets.NET does not provide any features for authenticating users. Instead, you integrate the XSockets:NET features into the existing authentication structure for an application. You authenticate users as you would normally in your application, and work with the results of the authentication in your XSockets.NET code. For example, you might authenticate your users with ASP.NET forms authentication, and then in your Controller, enforce which users or roles are authorized to call a method.

XSockets provides the Authorize attribute to specify which users have access to a controller or method. You apply the Authorize attribute to either a controller or particular methods in a controller. Without the Authorize attribute, all public methods on the controller are available to a client that is connected to the controller.

If you want to allow unrestrcited access on some methods you can add the AllowAnonymous attribute the these methods.

More information about attributes and methods below

Authorize Attribute

This attribute can be set on Controller or Method level. If set at controller level all action methods that do not have the AllowAnonymous attribute will require authentication.

The authorize attribute can take Roles and Users but if using that you will have to implement your own authentication by overriding OnAuthorization(AuthorizeAttribute authorizeAttribute)

AllowAnonymous Attribute

This attribute can be set on action methods and will then allow anonymous access.

Get FormsAuthentication Ticket

When you have custom authentication you can get the FormsAuthenticationTicket from this method.

var ticket = GetFormsAuthenticationTicket();

Note: If you do not pass in a cookiename .ASPXAUTH will be used.

Important: If you have separate project you will have to use the same origin to be able to get cookies and also use machine-key in the config to be able to get the AuthCookie. See http://msdn.microsoft.com/en-us/library/system.web.configuration.machinekeysection.compatibilitymode%28v=vs.110%29.aspx if you are using different framework versions in the projects.

Write a custom AuthenticationPipeline

When the socket is connected and the handshake is completed the AuthenticationPipeline will be called. By default the pipeline will look for a FormsAuthenticationTicket, but you can override this pipline by just implementing a interface XSockets.Core.Common.Socket.IXSocketAuthenticationPipeline

There can only be one pipeline so even if you implement several pipelines only one wil be used.

//using System.Security.Principal;
//using XSockets.Core.Common.Protocol;
//using XSockets.Core.Common.Socket;
//using XSockets.Plugin.Framework.Attributes;

[Export(typeof(IXSocketAuthenticationPipeline))]
public class MyAuthenticationPipeline : IXSocketAuthenticationPipeline
{
    public IPrincipal GetPrincipal(IXSocketProtocol protocol)
    {            
        if (protocol.ConnectionContext.User == null)
        {
            //creating a fake super user ;)
            var roles = new string[]{"superman","hulk"};
            var userIdentity = new GenericIdentity("David");
            protocol.ConnectionContext.User = new GenericPrincipal(userIdentity, roles);
        }            
        return protocol.ConnectionContext.User;
    }
}

How to override the OnAuthorization method

The OnAuthorization method is called for every method on a controller that has authentication. The attribute for the method (or controller) is passed in and we check that

  1. That the user is authenticated

  2. If the user name is required we verify a match

  3. If user name was not required or did not match we check roles

    //using System.Linq;
    //using XSockets.Core.Common.Socket.Attributes;
    //using XSockets.Core.XSocket;
    
    public virtual bool OnAuthorization(IAuthorizeAttribute authorizeAttribute)
    {
        try
        {
            var user = this.ProtocolInstance.ConnectionContext.User;
            if (user.Identity.IsAuthenticated)
            {
                if (!string.IsNullOrEmpty(authorizeAttribute.Roles) || !string.IsNullOrEmpty(authorizeAttribute.Users))
                {                    
                    if (authorizeAttribute.Users.Split(',').Contains(user.Identity.Name)){
                        return true;
                    }
                    return authorizeAttribute.Roles.Split(',').Any(user.IsInRole);      
                }
                return true;
            }
            return false;
        }
        catch
        {
            return false;
        }
    }
    

Example Based on the Write a custom AuthenticationPipeline where we added the username Hero and the roles hulk, superman we have the following scenario

//using XSockets.Core.Common.Socket.Attributes;

[Authorize()] //would be valid since we have a authorized `fake` user

[Authorize(Users = "David")] //would be valid

[Authorize(Roles = "batman,robin")] //would be invalid

[Authorize(Roles = "batman,hulk")] //would be valid

How to know when authorization fails

Every time a method on a controller needs authentication the OnAuthorization method is called (which was overridden in previous sample).

When the OnAuthorization returns false the OnAuthorizationFailed event is fired.

//using XSockets.Core.Common.Socket.Event.Arguments;
//using XSockets.Core.XSocket;

//Constructor
public Chat()
{
    this.OnAuthorizationFailed += Chat_OnAuthorizationFailed;
}

void Chat_OnAuthorizationFailed(object sender, OnAuthorizationFailedArgs e)
{
    Console.WriteLine("Auth Failed: {0},{1}", e.Controller, e.MethodName); 
}

The OnAuthorizationFailedArgs contains information about the controller and the method being called. Information about the user that called the method can be accessed from this.ProtocolInstance.ConnectionContext.User

###How to get information about the client from the ConnectionContext You can access various information about the connection from the IConnectionContext. The context is accessible from both Controller and Protocol.

this.ConnectionContext

The context contains information such as:

  • Cookies
  • Headers
  • Querystring
  • IPrincipal
  • PersistentId
  • Environment (is IDictionary<string,object>)

####Getting Cookies You can get the CookieCollection by using

var cookies = this.ProtocolInstance.ConnectionContext.CookieCollection;

Note: you will only be able to access cookies if your server is on the same domain as the cookie domain.

####Getting Headers You can get the headers NameValueCollection by using

var headers = this.ProtocolInstance.ConnectionContext.Headers;

####Getting Query Strings You can access the query string NameValueCollection by using

var querystring = this.ProtocolInstance.ConnectionContext.QueryString;

####Getting the current User (IPrincipal) You can get/set the IPrincipal by using

var principal = this.ProtocolInstance.ConnectionContext.User;

####Getting Environment info When you use custom protocols you can set this to be whatever you need/want.

var env = this.ProtocolInstance.ConnectionContext.Environment;