How to Enable AD FS Authentication (Part 2)
Want to learn more about how to enable AD FS authentication on your web application? Check out part two of this tutorial to learn more!
Join the DZone community and get the full member experience.
Join For FreeIntroduction
In part two of this series on how to enable AD FS authentication, we are going to learn more about the implementation of AD FS.
These are the steps that demonstrate the necessary precautions for a web application to make claims-based authorization decisions using AD FS. AzMan, a Windows Authorization Manager, is used to provide role-based access control via the acronym RBAC. The development tasks are:
Making the Application Federation-Aware
To make an application federation-aware, the following changes are required for its Web.config file. Once these changes are made, an application can then obtain claims from AD FS for the federation partners. It is important to make sure that the web application must also be identified and configured within the AD FS snap-in, which thus enables both the federation service and the .net application development to securely identify each other.
AD FS Web Agent Registration
AD FS provides a tool called the Web Agent. This tool runs in the IIS request pipeline as an extension HTTP module of type System.Web.Security.SingleSignOn.WebSsoAuthenticationModule. The AD FS Web Agent registers a handler for the HttpApplication.BeginRequest event that performs all the processing for query strings, cookies, and HTTP POST messages. It then obtains the identity or the security token of the user and decides whether to permit access to the application. An application must add the AD FS Web Agent to the web server or the modules section of its Web.config file, as shown in the below XML example.
<webServer>
<modules>
<add name="Adfs Web Agent"
type="System.Web.Security.SingleSignOn.WebSsoAuthenticationModule,
System.Web.Security.SingleSignOn,
Version=1.0.0.0, Culture=neutral,
PublicKeyToken=31BF3856AD364E35, Custom=null" />
</modules>
</webServer>
Custom Configuration Section and Handler Specification
The AD FS Web Agent needs to access the settings stored, which are in the Web.config file and uses a configuration section handler of type System.Web.Security.SingleSignOn.WebSsoConfigurationHandler to do so. These settings are stored in a custom section called the Web SSO. Then, the configuration file handler must be made aware of the custom section by specifying the section in the system.web section group, which is as shown in the following XML example:
<configSections>
<sectionGroup name="system.web">
<section name="websso"
type="System.Web.Security.SingleSignOn.WebSsoConfigurationHandler,
System.Web.Security.SingleSignOn,
Version=1.0.0.0, Culture=neutral,
PublicKeyToken=31BF3856AD364E35, Custom=null" />
</sectionGroup>
</configSections>
Add the Custom Section
In the custom web SSO section, the settings required by the AD FS Web Agent are specified and described in the following table.
Setting | Value |
FS | It is the URL for the resource AD FS server. |
returnurl |
It is the URL for a Web application, which is used by the AD FS Web Agent to redirect the user back to a Web application after validation. The return URL that must match the Application URL. And that is specified in the Web application's properties page i.e. in the AD FS snap-in which is located under Federation Service\Trust Policy\My Organization\Applications. |
cookies/path |
It is the path of the virtual directory for this Web application; case sensitive. |
authenticationrequired |
IT specifies whether authentication is required to access the Web application or not. The default is true, in which case the user cannot access the Web application without a valid AD FS cookie. When this element is missing or false, the user can then access the Web application anonymously. |
<websso>
<fs>https://someresourcefederationserver/adfs/fs/federationserverservice.asmx</fs>
<urls>
<returnurl>https://localhost/TreyOrdering/Default.aspx</returnurl>
</urls>
<cookies writecookies="true">
<path>/TreyOrdering</path>
</cookies>
<authenticationrequired />
</websso>
Reference the SingleSignOn Assemblies
Then, we have added references for the System.Web.Security.SingleSignOn
and System.Web.Security.SingleSignOn.ClaimTransforms
assemblies to enable the web application to access types in the System.Web.Security.SingleSignOn and System.Web.Security.SingleSignOn.Authorization namespaces, respectively.
Then, we also need to set the authentication mode to “None,” since authentication is performed by AD FS and not Internet Information Services (IIS).
<system.web>
<authentication mode="None" />
<compilation defaultLanguage="c#" debug="true">
<assemblies>
<add assembly="System.Web.Security.SingleSignOn,
Version=1.0.0.0, Culture=neutral,
PublicKeyToken=31BF3856AD364E35"/>
<add assembly="System.Web.Security.SingleSignOn.ClaimTransforms,
Version=1.0.0.0, Culture=neutral,
PublicKeyToken=31BF3856AD364E35"/>
</assemblies>
</compilation>
</system.web>
Obtain the SingleSignOnIdentity Object
Next, in the code for the web application, we should include the System.Web.Security.SingleSignOn namespace, which contains the SingleSignOnIdentity class, and the System.Web.Security.SingleSignOn.Authentication namespace, which contains the SecurityProperty and SecurityPropertyCollection classes. These namespaces help enable the application to use the AD FS infrastructure for authentication and access the claims it provides via the SAML token.
using System.Web.Security.SingleSignOn;
using System.Web.Security.SingleSignOn.Authorization;
Set the the SingleSignOnIdentity
object on the HttpContext.User property by the AD FS Web Agent, i.e. the WebSsoAuthenticationModule
. An application obtains the SingleSignOnIdentity
object during the Page_Load
event of the page life cylcle.
private void Page_Load(object sender, System.EventArgs e)
{
SingleSignOnIdentity SsoId = User.Identity as SingleSignOnIdentity;
}
Verify Authentication
The Web.config file for this example also includes the authenticationrequired
element, which, by default, has true value. This tells the AD FS Web Agent that the specified user must be authenticated before access to the web application is granted. If the authenticationrequired
element is not present or set to false, then the user can access the application anonymously. In case anonymous access is granted, use the SingleSignOnIdentity.IsAuthenticated property to check for authenticating the user.
if (SsoId.IsAuthenticated)
{
// ...
}
else
{
// Otherwise, this redirects the user to the resource AD FS Logon service.
SsoId.SignIn(Context);
}
Sometimes, whoever provided the authentication might be an important consideration before trust is granted to the user. You can use the SingleSignOnIdentity.AuthenticatingAuthority property for this.
Create a Client Context Using AzMan
The following code example illustrates how to connect to the AzMan trust policy store, obtain an object that represents this application's trust policy in the AzMan store, and create an empty client context. Subsequently, the client context will be populated with Group claims and used to make authorization decisions.
string connectionString = @"msxml://c:\AuthPolicy\AzStore.xml";
// Connect to the AzMan authorization policy store.
AzAuthorizationStoreClass azStore = new AzAuthorizationStoreClass();
azStore.Initialize(0, connectionString, null);
// Obtain the object associated with this application.
IazApplication2 azApplication =
azStore.OpenApplication("Trey Ordering", null);
// Create an empty client context.
IAzClientContext3 clientContext =
azApplication.InitializeClientContext2("Trey Ordering", null);
Retrieve Claims
The System.Web.Security.SingleSignOn.Authentication namespace contains the SecurityProperty and SecurityPropertyCollection classes. The SingleSignOnIdentity.SecurityPropertyCollection property returns a SecurityPropertyCollection instance, which contains a SecurityProperty object for each claim about the user. Group claims are added as roles to the AzMan client context. Identity and custom claims are added to a NameValueCollection object for convenient retrieval.
SecurityPropertyCollection claims = SsoId.SecurityPropertyCollection;
// Add all Group claims (as roles) to the AzMan client context.
clientContext.AddRoles(claims.GetRoles(), null);
// Store identity and custom claims in a NameValueCollection.
foreach (SecurityProperty claim in claims.GetIdentities())
{
nonGroupClaims.Add(claim.Name, claim.Value);
}
foreach (SecurityProperty claim in claims.GetProperties(
SecurityProperty.CustomClaimUri))
{
nonGroupClaims.Add(claim.Name, claim.Value);
}
Make Authorization Decisions
There are many ways to make authorization decisions. Three of the more common are discussed here:
- Using raw claims
- Using role checks
Using access checks
Access checks are preferable and make the application less coupled with policy.
Raw Claims
Raw claims from AD FS can be availed through the SecurityPropertyCollection
object. The following code example shows a decision based on the custom claim named EmployeeID, which, in the previous section, was retrieved and added to the nonGroupClaims NameValueCollection. Raw claims can be used in along with role and access checks.
if (Convert.ToInt32(nonGroupClaims["EmployeeID"]) == 321)
{
// Allow access.
}
Role Checks
The easiest means to make authorization decisions is to base them on roles using the IPrincipal.IsInRole method, which is available through HttpContext.User or the SecurityPropertyCollection.IsInRole method. The IsInRole property returns true if there is a Group claim equal to the role. Role checks do not provide the granularity that access checks allow.
if (User.IsInRole("Purchaser"))
{
// Allow access.
}
-or-
if (claims.IsInRole("Purchaser"))
{
// Allow access.
}
The client context obtained through AzMan can also be used for role checks, as the following code snippet demonstrates.
if (clientContext.IsInRoleAssignment("", "Purchaser") )
{
// Allow access.
}
Access Checks
AzMan is a tool used for access checks. It allows authorizations to be made based on specific operations, which are defined in the AzMan authorization policy store. In the following code example, access is granted to any user in an AzMan role (Group claim) that is allowed to perform operation #57.
// 57 corresponds to an OperationID defined in the AzMan store.
if (clientContext.AccessCheck2("Order #123", "", 57) == 0)
{
// Allow access for operation #57.
}
Conclusion
In part one, we learned the concepts behind AD FS authentication, and in this article, we learned the implementation. There are more things to learn about AD FS, but we just got started with some important concepts and implementation details.
Happy coding!
Opinions expressed by DZone contributors are their own.
Comments