Hi!
We have recently been working on hooking a couple of DNN sites up to federated login using SAML.
Our approach is to make a redirect to a STS when a user attempt to log on. After th user have authenticated with the STS and is redirected back to the DNN-site, we will inspect the claims and log the user in based on the username found in the claims collection.
We have successfully achieved that with some simple code, see below.
This was tested adding the code to Default.aspx.
To implement this function we want to intercept at the HTTP level but this is producing an error, see below. Not really sure why this is not working, since the code works when put in default.aspx…Some help would be greatly appreciated.
Error message when running this code as HTTPmodule.
InnerMessage:A claim of type 'http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier' or 'http://schemas.microsoft.com/accesscontrolservice/2010/07/claims/identityprovider' was not present on the provided ClaimsIdentity. To enable anti-forgery token support with claims-based authentication, please verify that the configured claims provider is providing both of these claims on the ClaimsIdentity instances it generates. If the configured claims provider instead uses a different claim type as a un
InnerStackTrace:
at System.Web.Helpers.AntiXsrf.ClaimUidExtractor.GetUniqueIdentifierParameters(ClaimsIdentity claimsIdentity, String uniqueClaimTypeIdentifier)
at System.Web.Helpers.AntiXsrf.ClaimUidExtractor.ExtractClaimUid(IIdentity identity)
at System.Web.Helpers.AntiXsrf.TokenValidator.GenerateFormToken(HttpContextBase httpContext, IIdentity identity, AntiForgeryToken cookieToken)
at System.Web.Helpers.AntiXsrf.AntiForgeryWorker.GetTokens(HttpContextBase httpContext, AntiForgeryToken oldCookieToken, AntiForgeryToken& newCookieToken, AntiForgeryToken& formToken)
at System.Web.Helpers.AntiXsrf.AntiForgeryWorker.GetFormInputElement(HttpContextBase httpContext)
at System.Web.Helpers.AntiForgery.GetHtml()
at DotNetNuke.Framework.ServicesFrameworkImpl.RegisterAjaxAntiForgery(Page page) in C:\VS2013_v4.5\DotNetNuke\DNN_DNN742Source\DNN Platform\Library\Framework\ServicesFrameworkImpl.cs:line 52
Code
HttpContext currentHttpContext = HttpContext.Current;
string realm = currentHttpContext.Request.Url.AbsoluteUri;
UserInfo objUserInfo = UserController.Instance.GetCurrentUserInfo();
int currentUserId = objUserInfo.UserID;
if (currentUserId < 1)
{
var sam = FederatedAuthentication.SessionAuthenticationModule;
var fam = new WSFederationAuthenticationModule();
fam.FederationConfiguration = FederatedAuthentication.FederationConfiguration;
var request = new HttpContextWrapper(currentHttpContext).Request;
// STS response type
if (!fam.IsSignInResponse(request))
{
//This is not a response from STS
//Url to the STS
fam.Issuer = sam.FederationConfiguration.WsFederationConfiguration.Issuer;
//Return address to pass on to the STS
fam.Realm = realm;
//Create the STS sign in request
var req = fam.CreateSignInRequest(string.Empty, null, false);
//Redirect to the STS
currentHttpContext.Response.Redirect(req.WriteQueryString());
}
else
{
//Resquest is response from STS and hence the user is already authenticated
//Get the SAML token
var securityToken = fam.GetSecurityToken(request);
var config = new SecurityTokenHandlerConfiguration
{
CertificateValidator = System.IdentityModel.Selectors.X509CertificateValidator.None,
IssuerNameRegistry = new CustomIssuerNameRegistry()
};
config.AudienceRestriction.AudienceMode = System.IdentityModel.Selectors.AudienceUriMode.Never;
var tokenHandler = new SamlSecurityTokenHandler
{
CertificateValidator = System.IdentityModel.Selectors.X509CertificateValidator.None,
Configuration = config
};
// validate the token and get the ClaimsIdentity out of it
var identity = tokenHandler.ValidateToken(securityToken);
var principal = new ClaimsPrincipal(identity);
var token = sam.CreateSessionSecurityToken(principal, string.Empty,
DateTime.Now.ToUniversalTime(), DateTime.Now.AddMinutes(20).ToUniversalTime(), false);
sam.WriteSessionTokenToCookie(token);
LogInDNNUser(principal);
currentHttpContext.Response.Redirect(currentHttpContext.Request.Url.AbsoluteUri, true);
}
}
private void LogInDNNUser(ClaimsPrincipal principal)
{
HttpContext currentHttpContext = HttpContext.Current;
//Get the portal settings
DotNetNuke.Entities.Portals.PortalSettings portal = DotNetNuke.Entities.Portals.PortalController.Instance.GetCurrentPortalSettings();
string accountName = "";
string email = "";
string firstName = "";
string lastName = "";
string displayName = "";
string name = "";
foreach (Claim claim in principal.Claims)
{
switch (claim.Type)
{
case "http://schemas.microsoft.com/ws/2008/06/identity/claims/windowsaccountname":
//Account name in from IDP
accountName = claim.Value;
break;
case "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress":
//E-mail address - used as username in DNN
email = claim.Value;
break;
case "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname":
//Given Name used as FirstName in DNN
firstName = claim.Value;
break;
case "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname":
//Surname used as LastName in DNN
lastName = claim.Value;
break;
case "http://schemas.xmlsoap.org/claims/CommonName":
//Common name - used as display name in DNN
displayName = claim.Value;
break;
case " http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name":
//Name - not used in DNN
name = claim.Value;
break;
}
}
UserInfo objUserInfo = UserController.GetUserByName(portal.PortalId, email);
if (objUserInfo == null)
{
EventLog.WriteEntry("User does no exist", EventLogEntryType.Information, 1000);
objUserInfo = new UserInfo();
objUserInfo.FirstName = firstName;
objUserInfo.LastName = lastName;
objUserInfo.DisplayName = firstName + ' ' + lastName;
objUserInfo.Username = email;
objUserInfo.Membership.Password = Guid.NewGuid().ToString().Substring(6);
objUserInfo.PortalID = portal.PortalId;
objUserInfo.Email = email;
CreateDNNUser(portal, objUserInfo);
}
try
{
//set the language to the default language of the portal
DotNetNuke.Services.Localization.Localization.SetLanguage(portal.DefaultLanguage);
//Log the user in
var loginStatus = new UserLoginStatus();
if (loginStatus != UserLoginStatus.LOGIN_FAILURE || loginStatus != UserLoginStatus.LOGIN_USERNOTAPPROVED)
{
UserController.UserLogin(portal.PortalId, objUserInfo, PortalSettings.PortalName, HttpContext.Current.Request.UserHostAddress, false);
}
}
catch (Exception ex)
{
Exceptions.LogException(ex);
}
}
protected void CreateDNNUser(DotNetNuke.Entities.Portals.PortalSettings currentPortal, UserInfo objUserInfo)
{
UserCreateStatus objUserCreateStatus = UserController.CreateUser(ref objUserInfo);
//Check if the user was added successfully
if (objUserCreateStatus != UserCreateStatus.Success)
{
//This will send the error to the error log, but the user will experience an infinite loop
throw new Exception("User not created successfully: " + objUserInfo.Username + "- " + objUserCreateStatus.ToString());
}
}