ict.ken.be

 

Posts in Category: .Net

WebApi Lifecycle 

Categories: .Net

Introduction to Identity and Access Control 

Categories: .Net Security

by Dominick Baier
dbaier@leastprivilege.com
http://www.leastprivilege.com
@leastprivilege Principals & Identities

interface IIdentity
{
	bool IsAuthenticated { get; }
	string AuthenticationType { get; }
	string Name { get; } 
}

interface IPrincipal
{
	IIdentity Identity { get; }
	bool IsInRole(string roleName);
}
  • Thread.CurrentPrincipal Every thread can have his own client security context Plumbing sets it, application gets it.
WindowsPrincipal
var id = WindowsIdentity.GetCurrent();
var principal = new WindowsPrincipal(id);

principal.IsInRole("Builtin\\Users") //Don't use because they are localized.
var localAdmins = new SecurityIdentifier(WellknownSidType.BuiltinAdministratorSid, null);
var domainAdmins = new SecurityIdentifier(WellknownSidType.AccountDomainAdminsSid, id.User.AccountDomainSid);
var users = new SecurityIdentifier(WellknownSidType.BuiltinUsersSid, null);

var account = new NTAccount(id.name);
var sid = account.Translate(typeof(SecurityIdentifier));

var groups = user.Groups.Translate(typeof(NTAccount));
GenericPrincipal

var roles = new string[] { "Sales", "Marketing" };
var p = new GenericPrincipal(new GenericIdentity("bob"), roles);
Thread.CurrentPrincipal = p;
p.Identity.Name
Role-based access control (RBAC)

if p.IsInRole("Sales") {} //returns true/false
new PrincipalPermission(null, "Development").Demand(); //will throw security exception if fails

[PrincipalPermission(SecurityAction.Demand, Role="Development"] //hard to unit test
private static void DoDevelopment() {}
  • Claims are statements
  • How do we handle things no longer in corporate network like cloud, partners and customers ?
  • Bell-Lapadula Model for goverment and military document security.

2002 Identity
2006 WCF System.IdentityModel with SecurityToken
2009 WIF Microsoft.IdentityModel with IClaimsIdentity & IClaimsPrincipal
2012 .NET 4.5 System.IdentityModel & System.Security.Claims eg. Bob is an administrator, Jim's email address is jim@foo.com, ...

public class Claim
{
	public virtual string Type { get; }
	public virtual string Value { get; }
	public virtual string Issuer { get; }
	//...
}

class ClaimsIdentity : IIdentity
{
	IEnumerable<Claim> Claims { get; }
}

class ClaimsPrincipal : IPrincipal
{
	ReadOnlyCollection<ClaimsIdentity> Identities { get; }	
}

var claim = new Claim("name", "dominick");
var claim = new Claim(ClaimTypes.Name, "dominick");

var Claims = new List<Claim>
{
	new Claim(ClaimTypes.Name, "dominick"),
	new Claim(ClaimTypes.Email, "dominick@foo.com"),
	new Claim(ClaimTypes.Role, "Geek"),
	new Claim("http://myClaims/location", "Heidelberg")
};

var id = new ClaimsIdentity(claims);
id.IsAuthenticated -> false because you can add claims to anonymous
var id = new ClaimsIdentity(claims, "Console App", ClaimTypes.Name, ClaimTypes.Role); //what do name and isrole map too for legacy
id.IsAuthenticated -> true

var cp = new ClaimsPrincipal(id); //prefered entry point
Thread.CurrentPrincipal = cp;
-> var cp = ClaimsPrincipal.Current;

var email = cp.FindFirst(ClaimTypes.Email).Value;

RolePrincipal, GenericPrincipal, WindowsPrincipal : ClaimsPrincipal : IPrincipal
Generalization & Specialization Interface level: IIdentity : Name, AuthenticationType, IsAuthenticated
Claims identity: ClaimsIdentity : Claims, FindAll(), FindFirst(), HasClaim()
Domain specific: WindowsIdentity : Token, Impersonate(), User/Device

  • Claims Always try to use ClaimsIdentity for your custom principal implementation.
class CorpIdentity : ClaimsIdentity
{
	public CorpIdentity(string name, string reportsTo, string office)
	{
		AddClaim(new Claim(ClaimTypes.Name, name));	
		AddClaim(new Claim("reportsto", reportsTo));	
		AddClaim(new Claim("office", office));	
	}
	
	public string office
	{
		get { return FindFirst("reportsto").Value; }	
	}
}
  • Services Unification of various credential formats to common ClaimsPrincipal representation Windows/Kerberos, Forms Authentication, HTTP basic authentication, SSL client certificates, WS-Security tokens, SAML, extensible, ...
  • Processing Pipeline Request (xml/binary/text) -> Security token handler (seserialization/validation) -> Claims transformation (skipped when session available) -> Security Session Management -> Session Security Token -> Authorization
public class ClaimsTransformer : ClaimsAuthenticationManager
{
	public overrride ClaimsPrincipal Authenticate(string resourceName, ClaimsPrincipal incomingPrincipal)
	{
		var name = incomingPrincipal.Identity.Name;
		if (string.IsNUllOrWhiteSpace(name)) throw new SecurityException("Name claim is missing");
		if (incomingPrincipal.Identity.IsAuthenticated)
		{
			return TransformClaims(incomingPrincipal);
		}
		return incomingPrincipal;
	}
}
<system.identityModel>
<identityConfiguration>
	<claimsAuthenticationManger type="assembly/class" />
</identityConfiguration>
</system.identityModel>
var p = new WindowsPrincipal(WindowsIdentity.GetCurrent());
Thread.CurrentPrincipal = FederationAuthentication.FederationConfiguration.identityConfiguration.ClaimsAuthenticationManager.Authenticate("none", p) as IPrincipal;
  •  Session management Preserve a ClaimsPrincipal across round trips (cookies, ws-secureconversation) 
var sessionToken = new SessionSecurityToken(principal, TimeSpan.FromHours(8));
FederatedAuthentication.SessionAuthenticationModule.WriteSessionTokenToCookie(sessionToken);
  • Data protection api, zero configuration but only for single server.
  • For webfarms use machinekey or ssl-certificate to protect your cookie.
  • Roundtrip the identity and cache the claims principal.
  • Claims authorization manager Extensibility point for loading/parsing authorization policy
  • Extensibility point for mapping operations/resources to required claims
  • Auto-invoked during request processing
  • Application code should not check for claims directly 
public class AuthorizationContext
{
	public AuthorizationContext();
	public Collection<Claim> Action { get; }
	public ClaimsPrincipal Principal { get; }
	public Collection<Claim> Resource { get; }
}

<claimsAuthorizationManager type="ClaimsAuthorizationManagerClass, theAssembly" >
	<policy file="foo.xml" /> 
</claimsAuthorizationManager>
public class ClaimAuthZManager : ClaimsAuthorizationManager
{
	public override bool CheckAccess(AuthorizationContext context)
	{
		//inspect context and make authorization decision
		var resource = context.Resource.First().Value;
		var action = context.Action.First().Value;
		if (action == "Show" && resource == "Castle")
		{
			var hasCastle = context.Principal.HasClaim("http://myclaims/hasCastle", "true");
			return hasCastle;
		}
		return false;
	}
	override void LoadCustomConfiguration(XmlNodeList nodelist)
	{
		base.LoadCustomConfiguration(nodelist);
	}
}
[ClaimsPrincipalPermission(SecurityAction.Demand, Operation = "Add", Resource = "Customer")]
public void AddCustomer(Customer customer) { ... }
void Print(Document document)
{
	if (ClaimsPrincipalPermission.CheckAccess(document.Printer, "Print")) { ... }
}
var authZ = FederatedAuthentication.FederationConfiguration.IdentityConfiguration.Claims.ClaimsAuthZManager;
authZ.CheckAccess(...);

http://msdn.microsoft.com/en-us/library/system.security.claims.claimsauthorizationmanager.aspx

Protocol support

  • Web Application : WS-Federation
  • SOAP : WS-Trust & WS-Security
  • WebApi : OAuth2 Client -> STS -> Token -> Client -> Token -> Relying Party/Application (no authentication on RP) <saml:Assertion ... Signature ...> tokens for seamless third party authentication

Security Token Services

  • Microsoft Active Directory
  • Federation Service 2
  • IBM Tivoli Federation Manager
  • Oracle Identity Manager
  • Ping Federate
  • Thinktecture .NET 4.5 (http://identityserver.codeplex.com/) ASP.Net
<authentication mode="windows">
	<forms loginUrl="~/Account/Login" timeout="2880" />
</authentication>

<system.identityModel configSource="identity.config" />
<system.identityModel>
	<identityConfiguration>
		<audienceUris />>
		<claimsAuthenticationManager type="Security.ClaimsTransformer, Web" />
		<issuerNameRegistry />
	</identityConfiguration>
</system.identityModel>

private void EstablishSession(ClaimsPrincipal principal)
{
	if (HttpContext.Current != null)
	{
		var sessionToken = new SessionSecurityToken(principal);
		FederatedAuthentication.SessionAuthenticationModule.WriteSessionTokenToCookie(sessionToken);
	}
}
<system.webServer>
	<add name="ClaimsTransformationModule" type="Security.ClaimsTransformationHttpModule" />
	<add name="SessionAuthenticationModule" type="Security.IdentityModel.Services.SessionAuthenticationModule, ..." />
</system.webServer>

<system.identityModel.services configSource="identity.Services.config" />
<system.identityModel.services>
	<federationConfiguration>
		<wsFederation passiveRedirectionEnable="true" issuer="remote login page location"
		realm="" requireHttps="true" />
		<cookieHandler requireSsl="true" />
	</federationConfiguration>
</system.identityModel>

for wcf: <bindings> <ws2007FederationHttpBinding>

webapi

[Authorize]
public class IdentityController : ApiController
{
	public Identity Get()
	{
		return new Identity(User.Identity);
	}
}

AutoMapper vs Emit vs ValueInjector vs Glue 

Categories: .Net
I did some small tests on mapping tools and as expected AutoMapper is ‘best of the test’. However if you are doing semi-automatic (only map the ones that are different manually), you will get 6 times faster results with Emit. I think that coding ease should prevail and you should use a caching layer to cover-up this difference.
 
TEST RESULTS - 4 oct 2012 - N = 300000
  1. Automapper for coding ease and multiple features.
  2. Emit when needing speed and you can apply an algorithm. (faster for simple cases)
  3. ValueInjecter has almost same features as Emit but slower. And in AutoMapper simulation mode incredible slow. (obsolete)
  4. Glue is too slow. (obsolete)

C# Disposal Pattern 

Categories: .Net Patterns
class MyResourceWrapper : IDisposable
{
    // Used to determine if Dispose()
    // has already been called.
    private bool disposed = false;
    
    public void Dispose()
    {
        // Call our helper method.
        // Specifying "true" signifies that
        // the object user triggered the cleanup.
        CleanUp(true);
        // Now suppress finalization.
        GC.SuppressFinalize(this);
    }
    
    private void CleanUp(bool disposing)
    {
        // Be sure we have not already been disposed!
        if (!this.disposed)
        {
            // If disposing equals true, dispose all
            // managed resources.
            if (disposing)
            {
                // Dispose managed resources.
            }
            // Clean up unmanaged resources here.
        }
        disposed = true;
    }

    ~MyResourceWrapper()
    {
        // Call our helper method.
        // Specifying "false" signifies that
        // the GC triggered the cleanup.
        CleanUp(false);
    }
}
Page 3 of 5 << < 1 2 3 4 5 > >>