public ClaimsPrincipal Transform(ClaimsPrincipal principal, IDictionary <string, string> inputs, IExternalClaimTransformationPipelineContext pipelineContext) { if (principal == null) { throw new ArgumentNullException("principal"); } try { var identity = principal.Identities.FirstOrDefault(x => x.BootstrapContext != null); if (identity == null) { identifyLogWriter.WriteDebug("No Identify has BootstrapContext"); return(principal); } var bootstrapContext = identity.BootstrapContext as BootstrapContext; if (bootstrapContext == null) { identifyLogWriter.WriteDebug("The identity.BootstrapContext object is not of BootstrapContext type."); return(principal); } identifyLogWriter.WriteDebug("The identity.BootstrapContext is valid"); } catch (InvalidOperationException ex) // this exception type is caught for illustration purpose only { // Ids from 4830 to 4899 are reserved for external components. Pick one that doesn't conflict with other external events in the same set up identifyLogWriter.WriteError(4830, ex); } return(principal); }
private bool VerifyIfUserNameIsCorrect(string username, IIdentifyLogWriter logWriter) { if (username.Equals("unknownusername", StringComparison.InvariantCultureIgnoreCase)) { logWriter.WriteError($"Incorrect passord {username}"); return(false); } return(true); }
private bool VerifyPasswordIsCorrect(string password, IIdentifyLogWriter logWriter) { if (password.Equals("incorrectpassword", StringComparison.InvariantCultureIgnoreCase)) { logWriter.WriteError($"Incorrect passord {password}"); return(false); } return(true); }
/// <summary> /// Validate credentials by generic provider /// </summary> /// <param name="cc">Notice that on STs the controller context is irrelevant</param> /// <param name="inputs"></param> /// <param name="logWriter"></param> /// <returns></returns> public CredentialsValidationResult Validate(ControllerContext cc, IDictionary <string, string> inputs, IIdentifyLogWriter logWriter) { var validationResult = ValidateInput(inputs); if (validationResult.ResultCode != CredentialsValidationResultCode.Success) { logWriter.WriteError("Validate the input failed. Error code: " + validationResult.ResultCode + ". ExternalErrorMessages: " + string.Join("\n-", validationResult.ExternalErrorMessages)); validationResult.ShowErrorViewWhenResultCodeIsNotSuccess = false; return(validationResult); } var username = inputs[UserName]; var password = inputs[Password]; var serviceIdentifier = inputs[ServiceIdentifier]; if (!VerifyIfUserNameIsCorrect(username, logWriter)) { return(new CredentialsValidationResult { ResultCode = CredentialsValidationResultCode.UnknownUserName }); } if (!VerifyPasswordIsCorrect(password, logWriter)) { return(new CredentialsValidationResult { ResultCode = CredentialsValidationResultCode.IncorrectPassword }); } var logResult = new StringBuilder(); logResult.AppendLine( $"Successfully validate generic credentials for username = '******' with service identifier ='{serviceIdentifier}'"); logResult.AppendLine(""); // For this example, we are returning only claims whose types start with "additionalClaims". In reality, here is where you put on your business logic code to return claims. var identity = new ClaimsIdentity(AuthenticationTypes.Password); foreach (var input in inputs) { if (input.Key.StartsWith(AdditionalClaims, StringComparison.InvariantCultureIgnoreCase)) { identity.AddClaim(new Claim(input.Key, input.Value)); logResult.AppendLine($"Additional claims received: type = '{input.Key}' - value ='{input.Value}'"); if (input.Value.Equals("exception")) { throw new GenericProviderSampleException("Generic provider exception is thrown on UsernamePasswordGenericCredentialsValidator as requested"); } } } logWriter.WriteInformation(logResult); return(new CredentialsValidationResult { ResultCode = CredentialsValidationResultCode.Success, ClaimsPrincipal = new ClaimsPrincipal(identity) }); }
public ClaimsPrincipal Transform(ClaimsPrincipal principal, IDictionary <string, string> inputs, IExternalClaimTransformationPipelineContext pipelineContext) { if (principal == null) { throw new ArgumentNullException("principal"); } try { var type = GetType(); // each identity provider may add its own identity to the claims principal object // at the time the principal object is passed to this transformation rule, how many identities it contains depends on // what previous transformations it has gone through. // Normally speaking: // 1. After Identify receives a token from an upstream Idp or from the UserNamePassword login, it creates the principal with one identity. // 2. After that, Identify loads claims from the local store into another identity and adds it to the principal (2 identities so far) // 3. There is a setting called "Execute before loading claims from local store" in the claims transformation configuration page which controls // if a transformation should be executed before or after the second identity is added. // 4. Note 1: Other transformations may add more identities to the claims principal. // 5. Note 2: One can choose to add claims to one identity or to all identities depending on specific need. foreach (var identity in principal.Identities) { identity.AddClaim(new Claim(type.FullName, type.AssemblyQualifiedName)); identifyLogWriter.WriteInformation(string.Format(CultureInfo.InvariantCulture, "A new claim is added: [{0},{1}]", type.FullName, type.AssemblyQualifiedName)); } AddConnectionEntityIdentifiers(principal); } catch (InvalidOperationException ex) // this exception type is caught for illustration purpose only { // Ids from 4830 to 4899 are reserved for external components. Pick one that doesn't conflict with other external events in the same set up identifyLogWriter.WriteError(4830, ex); } return(principal); }
public IEnumerable <UserProfile> GetUserProfiles(ControllerContext cc, ClaimsPrincipal principal, IDictionary <string, string> input, string contextId) { #region sanity checks if (cc == null) { throw new ArgumentNullException("cc"); } if (principal == null) { throw new ArgumentNullException("principal"); } if (input == null) { throw new ArgumentNullException("input"); } if (contextId == null) { throw new ArgumentNullException("contextId"); } #endregion if (!input.ContainsKey("identityAttributeName")) { // can write event with id to event log. logWriter.WriteError(9999, "The input key-value dictionary doesn't contain identity attribute name. That attribute name is needed to do a look up against a Ldap store"); throw new ArgumentException( "The input key-value dictionary doesn't contain identity attribute name. That attribute name is needed to do a look up against a Ldap store"); } if (!input.ContainsKey("ldapwsServerName")) { throw new ArgumentException( "The input key-value dictionary doesn't contain a ldapWS server name (whose key is ldapwsServerName). That ldapWS server name is needed to do a look up against a Ldap store"); } string identityAttributeName = input["identityAttributeName"]; string ldapwsServerName = input["ldapwsServerName"]; // we need to know what user's attribute value should be used to compare against the identityattribute in Ldap // default value string identityValue = principal.Identity.Name; // check if another claim is specified whose value to be used to look up in Ldap if (input.ContainsKey("identityClaimType")) { Claim identityClaim = principal.Claims.FirstOrDefault(claim => claim.Type == input["identityClaimType"]); if (identityClaim != null) { identityValue = identityClaim.Value; } } // here we assume that attributes to fetch have keys which start with ldapattr_ var additionalAttributes = input.Where(kvp => kvp.Key.StartsWith("ldapattr_")).Select(kvp => kvp.Value); IEnumerable <IDictionary <string, object> > users = identifyLdapStore.GetUsers(identityAttributeName, identityValue, ldapwsServerName, additionalAttributes); List <UserProfile> userProfiles = new List <UserProfile>(); foreach (var user in users) { // how to map a user object to a user profile depends on specific scenarios. // An easy way is to make hard-mapping between a ldap attribute and a userProfile like in this example // A more flexible way is to pass such a mapping to this method via the input parameter. The mapping is configured via a UI in Identify*Admin // For example: // {prop_identity, samAccountName} // {prop_email, mail} // {prop_photourl, url} var userProfile = new UserProfile(); userProfile.Identity = user["sAMAccountName"].ToString(); const string displayNameAttr = "Display-Name"; if (user.ContainsKey(displayNameAttr) && user[displayNameAttr] != null) { userProfile.DisplayName = user[displayNameAttr].ToString(); } const string mailAttr = "mail"; if (user.ContainsKey(mailAttr) && user[mailAttr] != null) { userProfile.Email = user[mailAttr].ToString(); } const string photoUrlAttr = "url"; if (user.ContainsKey(photoUrlAttr) && user[photoUrlAttr] != null) { userProfile.PhotoUrl = user[photoUrlAttr].ToString(); } userProfile.Attributes = user; // finally, assign the "user" object to the Attributes property just in case the caller needs it userProfiles.Add(userProfile); } return(userProfiles); }
public CredentialsValidationResult Validate(ControllerContext cc, IDictionary <string, string> input, IIdentifyLogWriter logWriter) { var validationResult = ValidateInput(input); LookupProtocolConnection(cc, logWriter); if (validationResult.ResultCode != CredentialsValidationResultCode.Success) { logWriter.WriteWarning("Validate the input failed. Error code: " + validationResult.ResultCode + ". ExternalErrorMessages: " + string.Join("\n-", validationResult.ExternalErrorMessages)); validationResult.ShowErrorViewWhenResultCodeIsNotSuccess = true; return(validationResult); } var connectionString = input[ConnectionString]; try { var userRepository = new DummyUserRepository(connectionString); var username = input[UserName].Trim(); var user = userRepository.GetUserByName(username); if (user == null) { logWriter.WriteInformation("User not found. Search username: "******"User information: [UserName: {0}], [Password: {1}], [IsDisabled: {2}], [IsLocked: {3}]", user.Username, user.Password, user.IsDisabled, user.IsLocked)); var password = input[Password].Trim(); if (user.Password.Trim() != password) { validationResult.ExternalErrorMessages.Add("Password is invalid. Expected: " + user.Password); validationResult.ResultCode = CredentialsValidationResultCode.IncorrectPassword; } else if (user.IsDisabled) { validationResult.ResultCode = CredentialsValidationResultCode.UserDisabled; } else if (user.IsLocked) { validationResult.ResultCode = CredentialsValidationResultCode.UserLocked; } else { validationResult.UserIdentity = user.Username; validationResult.ResultCode = CredentialsValidationResultCode.Success; } } } catch (Exception ex) { logWriter.WriteError("An unexpected exception happends. Error message: " + ex.Message + ". StackTrace: " + ex.StackTrace); validationResult.ResultCode = CredentialsValidationResultCode.UnknownError; validationResult.ExternalErrorMessages.Add(ex.Message); } logWriter.WriteInformation("Validation with result code: " + validationResult.ResultCode + ". ExternalErrorMessages: " + string.Join("\n-", validationResult.ExternalErrorMessages)); validationResult.ShowErrorViewWhenResultCodeIsNotSuccess = true; return(validationResult); }
public IEnumerable <UserProfile> GetUserProfiles(ControllerContext cc, ClaimsPrincipal principal, IDictionary <string, string> input, string contextId) { #region sanity checks if (cc == null) { throw new ArgumentNullException("cc"); } if (principal == null) { throw new ArgumentNullException("principal"); } if (input == null) { throw new ArgumentNullException("input"); } if (contextId == null) { throw new ArgumentNullException("contextId"); } #endregion if (!input.ContainsKey("identityLocalClaimType")) { const string errorMessage = "The input key-value dictionary doesn't contain identity claim name. That attribute name is needed to do a look up against a local user store"; // can write event with id to event log. logWriter.WriteError(9999, errorMessage); throw new ArgumentException(errorMessage); } string identityAttributeName = input["identityLocalClaimType"]; // we need to know what user's claim value should be used to compare against the claim type in local store // default value string identityValue = principal.Identity.Name; // check if another claim is specified whose value to be used to look up in Ldap if (input.ContainsKey("identityClaimType")) { Claim identityClaim = principal.Claims.FirstOrDefault(claim => claim.Type == input["identityClaimType"]); if (identityClaim != null) { identityValue = identityClaim.Value; } } IEnumerable <IDictionary <string, object> > users = identifyLocalStore.GetUsers(identityAttributeName, identityValue); List <UserProfile> userProfiles = new List <UserProfile>(); foreach (var user in users) { // how to map a user object to a user profile depends on specific scenarios. // An easy way is to make hard-mapping between a claim and a userProfile like in this example // A more flexible way is to pass such a mapping to this method via the input parameter. The mapping is configured via a UI in Identify*Admin // For example: // {prop_identity, http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name} // {prop_email, http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress } // {prop_photourl, urn:safewhere:photo:url} var userProfile = new UserProfile(); // This sample assumes that the real username is stored with the claim type below userProfile.Identity = ((List <string>)user["http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name"]).First(); // __IdentifyUserName is a reserved key for Identify's user name (aka display name) // The other two are __Organization and __Group const string displayNameAttr = "__IdentifyUserName"; if (user.ContainsKey(displayNameAttr) && user[displayNameAttr] != null) { userProfile.DisplayName = user[displayNameAttr].ToString(); } // This sample assumes that the real email is stored with the claim type below const string mailAttr = "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress"; if (user.ContainsKey(mailAttr) && user[mailAttr] != null) { userProfile.Email = GetClaimValue(user[mailAttr]); } const string photoUrlAttr = "urn:photourl"; if (user.ContainsKey(photoUrlAttr) && user[photoUrlAttr] != null) { userProfile.PhotoUrl = GetClaimValue(user[photoUrlAttr].ToString()); } userProfile.Attributes = user; // finally, assign the "user" object to the Attributes property just in case the caller needs it userProfiles.Add(userProfile); } return(userProfiles); }