protected override void SetAuthPrincipalEnableStatus(AuthenticablePrincipal ap, bool enable) { Debug.Assert(ap.fakePrincipal == false); bool acctDisabled; DirectoryEntry de = (DirectoryEntry)ap.UnderlyingObject; if (de.Properties["msDS-UserAccountDisabled"].Count > 0) { Debug.Assert(de.Properties["msDS-UserAccountDisabled"].Count == 1); acctDisabled = (bool)de.Properties["msDS-UserAccountDisabled"][0]; } else { // Since we loaded the properties, we should have it. Perhaps we don't have access // to it. In that case, we don't want to blindly overwrite whatever other bits might be there. GlobalDebug.WriteLineIf(GlobalDebug.Warn, "ADAMStoreCtx", "SetAuthPrincipalEnableStatus: can't read userAccountControl"); throw new PrincipalOperationException( StringResources.ADStoreCtxUnableToReadExistingAccountControlFlagsToEnable); } if ((enable && acctDisabled) || (!enable && !acctDisabled)) { GlobalDebug.WriteLineIf(GlobalDebug.Warn, "ADAMStoreCtx", "SetAuthPrincipalEnableStatus: Enabling (old enabled ={0} new enabled= {1})", !acctDisabled, enable); WriteAttribute<bool>(ap, "msDS-UserAccountDisabled", !enable); } }
internal abstract void UnexpirePassword(AuthenticablePrincipal p);
internal abstract CredentialTypes SupportedCredTypes(AuthenticablePrincipal p);
internal abstract bool IsLockedOut(AuthenticablePrincipal p);
internal abstract void ChangePassword(AuthenticablePrincipal p, string oldPassword, string newPassword);
internal override void SetPassword(AuthenticablePrincipal p, string newPassword) { DirectoryEntry underlyingObject = (DirectoryEntry)p.UnderlyingObject; this.SetupPasswordModification(p); SDSUtils.SetPassword(underlyingObject, newPassword); }
internal override void InitializeUserAccountControl(AuthenticablePrincipal p) { }
internal PasswordInfo(AuthenticablePrincipal principal) { _owningPrincipal = principal; }
/// <summary> /// This method sets the default user account control bits for the new principal /// being created in this account store. /// </summary> /// <param name="p"> Principal to set the user account control bits for </param> internal override void InitializeUserAccountControl(AuthenticablePrincipal p) { // In ADAM, there is no user account control property that needs to be initialized // so do nothing }
/// <summary> /// Change the password on the principal /// </summary> /// <param name="p">Principal to modify</param> /// <param name="oldPassword">Current password</param> /// <param name="newPassword">New password</param> internal override void ChangePassword(AuthenticablePrincipal p, string oldPassword, string newPassword) { Debug.Assert(p.fakePrincipal == false); // Shouldn't be being called if this is the case Debug.Assert(p.unpersisted == false); Debug.Assert(p != null); Debug.Assert(newPassword != null); // but it could be an empty string Debug.Assert(oldPassword != null); // but it could be an empty string DirectoryEntry de = (DirectoryEntry)p.UnderlyingObject; Debug.Assert(de != null); SetupPasswordModification(p); SDSUtils.ChangePassword(de, oldPassword, newPassword); }
internal override void SetPassword(AuthenticablePrincipal p, string newPassword) { Debug.Assert(p.fakePrincipal == false); Debug.Assert(p != null); Debug.Assert(newPassword != null); // but it could be an empty string DirectoryEntry de = (DirectoryEntry)p.UnderlyingObject; Debug.Assert(de != null); SetupPasswordModification(p); SDSUtils.SetPassword(de, newPassword); }
// modifies the connections settings for the upcoming password operation.. // If Signing + Sealing are enabled on the connection a direct call to SetPassword will always fail for ADAM. // ADSI will first attempt to set the password over SSL which will fail because double encryption is not supported. // It will then try KetSetPassword and NetApi which will both always fail against ADAM. // We need to tell ADSI to send a clear text password which is not actually clear text because // the initial connection is encrypted with sign + seal. Once this call is made the user needs to call CleanupAfterPasswordModification // To reset the options that were modified. private void SetupPasswordModification(AuthenticablePrincipal p) { DirectoryEntry de = (DirectoryEntry)p.UnderlyingObject; if (((this.contextOptions & ContextOptions.Signing) != 0) && ((this.contextOptions & ContextOptions.Sealing) != 0)) { try { de.Invoke("SetOption", new object[]{UnsafeNativeMethods.ADS_OPTION_ENUM.ADS_OPTION_PASSWORD_METHOD, UnsafeNativeMethods.ADS_PASSWORD_ENCODING_ENUM.ADS_PASSWORD_ENCODE_CLEAR}); de.Options.PasswordPort = p.Context.ServerInformation.portLDAP; } catch (System.Reflection.TargetInvocationException e) { GlobalDebug.WriteLineIf(GlobalDebug.Error, "ADAMStoreCtx", "SetupPasswordModification: caught TargetInvocationException with message " + e.Message); if (e.InnerException is System.Runtime.InteropServices.COMException) { throw (ExceptionHelper.GetExceptionFromCOMException((System.Runtime.InteropServices.COMException)e.InnerException)); } // Unknown exception. We don't want to suppress it. throw; } } }
internal override void ExpirePassword(AuthenticablePrincipal p) { if (p as ComputerPrincipal == null) { this.WriteAttribute(p, "PasswordExpired", 1); return; } else { throw new InvalidOperationException(StringResources.SAMStoreCtxNoComputerPasswordExpire); } }
internal override void ChangePassword(AuthenticablePrincipal p, string oldPassword, string newPassword) { if (p as ComputerPrincipal == null) { DirectoryEntry underlyingObject = (DirectoryEntry)p.UnderlyingObject; SDSUtils.ChangePassword(underlyingObject, oldPassword, newPassword); return; } else { throw new InvalidOperationException(StringResources.SAMStoreCtxNoComputerPasswordSet); } }
private void WriteAttribute(AuthenticablePrincipal p, string attribute, int value) { DirectoryEntry underlyingObject = (DirectoryEntry)p.UnderlyingObject; SDSUtils.WriteAttribute(underlyingObject.Path, attribute, value, this.credentials, this.authTypes); }
// Returns the set of credential types supported by this store for the specified principal. // Used when a application tries to access the PasswordInfo property of a newly-inserted // (not yet persisted) AuthenticablePrincipal, to determine whether it should be allowed. // Also used to implement AuthenticablePrincipal.SupportedCredentialTypes. internal override CredentialTypes SupportedCredTypes(AuthenticablePrincipal p) { // Fake principals do not have store objects, so they certainly don't have stored creds. if (p.fakePrincipal) return (CredentialTypes)0; CredentialTypes supportedTypes = CredentialTypes.Password; // Longhorn SAM supports certificate-based authentication if (this.IsLSAM) supportedTypes |= CredentialTypes.Certificate; return supportedTypes; }
// // Special operations: the Principal classes delegate their implementation of many of the // special methods to their underlying StoreCtx // // methods for manipulating accounts /// <summary> /// This method sets the default user account control bits for the new principal /// being created in this account store. /// </summary> /// <param name="p"> Principal to set the user account control bits for </param> internal override void InitializeUserAccountControl(AuthenticablePrincipal p) { Debug.Assert(p != null); Debug.Assert(p.fakePrincipal == false); Debug.Assert(p.unpersisted == true); // should only ever be called for new principals // set the userAccountControl bits on the underlying directory entry DirectoryEntry de = (DirectoryEntry)p.UnderlyingObject; Debug.Assert(de != null); Type principalType = p.GetType(); if ((principalType == typeof(UserPrincipal)) || (principalType.IsSubclassOf(typeof(UserPrincipal)))) { de.Properties["userFlags"].Value = SDSUtils.SAM_DefaultUAC; } }
internal PasswordInfo(AuthenticablePrincipal principal) { this.lastPasswordSet = null; this.lastBadPasswordAttempt = null; this.owningPrincipal = principal; }
internal override bool IsLockedOut(AuthenticablePrincipal p) { Debug.Assert(p.fakePrincipal == false); Debug.Assert(p.unpersisted == false); DirectoryEntry de = (DirectoryEntry)p.UnderlyingObject; Debug.Assert(de != null); try { de.RefreshCache(); return (bool)de.InvokeGet("IsAccountLocked"); } catch (System.Reflection.TargetInvocationException e) { if (e.InnerException is System.Runtime.InteropServices.COMException) { throw (ExceptionHelper.GetExceptionFromCOMException((System.Runtime.InteropServices.COMException)e.InnerException)); } throw; } }
protected override void SetAuthPrincipalEnableStatus(AuthenticablePrincipal ap, bool enable) { DirectoryEntry underlyingObject = (DirectoryEntry)ap.UnderlyingObject; if (underlyingObject.Properties["msDS-UserAccountDisabled"].Count <= 0) { throw new PrincipalOperationException(StringResources.ADStoreCtxUnableToReadExistingAccountControlFlagsToEnable); } else { bool item = (bool)underlyingObject.Properties["msDS-UserAccountDisabled"][0]; if (enable && item || !enable && !item) { base.WriteAttribute<bool>(ap, "msDS-UserAccountDisabled", !enable); } return; } }
internal override void UnlockAccount(AuthenticablePrincipal p) { GlobalDebug.WriteLineIf(GlobalDebug.Info, "SAMStoreCtx", "UnlockAccount"); Debug.Assert(p.fakePrincipal == false); Debug.Assert(p.unpersisted == false); // Computer accounts are never locked out, so nothing to do if (p is ComputerPrincipal) { GlobalDebug.WriteLineIf(GlobalDebug.Info, "SAMStoreCtx", "UnlockAccount: computer acct, skipping"); return; } DirectoryEntry de = (DirectoryEntry)p.UnderlyingObject; Debug.Assert(de != null); // After setting the property, we need to commit the change to the store. // We do it in a copy of de, so that we don't inadvertently commit any other // pending changes in de. DirectoryEntry copyOfDe = null; try { copyOfDe = SDSUtils.BuildDirectoryEntry(de.Path, _credentials, _authTypes); Debug.Assert(copyOfDe != null); copyOfDe.InvokeSet("IsAccountLocked", new object[] { false }); copyOfDe.CommitChanges(); } catch (System.Runtime.InteropServices.COMException e) { // ADSI threw an exception trying to write the change GlobalDebug.WriteLineIf(GlobalDebug.Error, "SAMStoreCtx", "UnlockAccount: caught COMException, message={0}", e.Message); throw ExceptionHelper.GetExceptionFromCOMException(e); } finally { if (copyOfDe != null) copyOfDe.Dispose(); } }
private void SetupPasswordModification(AuthenticablePrincipal p) { DirectoryEntry underlyingObject = (DirectoryEntry)p.UnderlyingObject; if ((this.contextOptions & ContextOptions.Signing) != 0 && (this.contextOptions & ContextOptions.Sealing) != 0) { try { object[] objArray = new object[2]; objArray[0] = UnsafeNativeMethods.ADS_OPTION_ENUM.ADS_OPTION_PASSWORD_METHOD; objArray[1] = UnsafeNativeMethods.ADS_PASSWORD_ENCODING_ENUM.ADS_PASSWORD_ENCODE_CLEAR; underlyingObject.Invoke("SetOption", objArray); underlyingObject.Options.PasswordPort = p.Context.ServerInformation.portLDAP; } catch (TargetInvocationException targetInvocationException1) { TargetInvocationException targetInvocationException = targetInvocationException1; if (targetInvocationException.InnerException as COMException == null) { throw; } else { throw ExceptionHelper.GetExceptionFromCOMException((COMException)targetInvocationException.InnerException); } } } }
internal override void ChangePassword(AuthenticablePrincipal p, string oldPassword, string newPassword) { Debug.Assert(p.fakePrincipal == false); Debug.Assert(p is UserPrincipal || p is ComputerPrincipal); // Shouldn't be being called if this is the case Debug.Assert(p.unpersisted == false); // ********** In SAM, computer accounts don't have a change password method if (p is ComputerPrincipal) { GlobalDebug.WriteLineIf(GlobalDebug.Warn, "SAMStoreCtx", "ChangePassword: computer acct, can't change"); throw new InvalidOperationException(StringResources.SAMStoreCtxNoComputerPasswordSet); } Debug.Assert(p != null); Debug.Assert(newPassword != null); // but it could be an empty string Debug.Assert(oldPassword != null); // but it could be an empty string DirectoryEntry de = (DirectoryEntry)p.UnderlyingObject; Debug.Assert(de != null); SDSUtils.ChangePassword(de, oldPassword, newPassword); }
internal abstract void InitializeUserAccountControl(AuthenticablePrincipal p);
internal override void UnexpirePassword(AuthenticablePrincipal p) { Debug.Assert(p.fakePrincipal == false); // ********** In SAM, computer accounts don't have a password-expired property if (p is ComputerPrincipal) { GlobalDebug.WriteLineIf(GlobalDebug.Warn, "SAMStoreCtx", "UnexpirePassword: computer acct, can't unexpire"); throw new InvalidOperationException(StringResources.SAMStoreCtxNoComputerPasswordExpire); } WriteAttribute(p, "PasswordExpired", 0); }
internal abstract void SetPassword(AuthenticablePrincipal p, string newPassword);
private void WriteAttribute(AuthenticablePrincipal p, string attribute, int value) { Debug.Assert(p is UserPrincipal || p is ComputerPrincipal); Debug.Assert(p != null); DirectoryEntry de = (DirectoryEntry)p.UnderlyingObject; SDSUtils.WriteAttribute(de.Path, attribute, value, _credentials, _authTypes); }
internal abstract bool SupportsAccounts(AuthenticablePrincipal p);
// // Data Validation // // Returns true if AccountInfo is supported for the specified principal, false otherwise. // Used when a application tries to access the AccountInfo property of a newly-inserted // (not yet persisted) AuthenticablePrincipal, to determine whether it should be allowed. internal override bool SupportsAccounts(AuthenticablePrincipal p) { // Fake principals do not have store objects, so they certainly don't have stored account info. if (p.fakePrincipal) return false; // Both Computer and User support accounts. return true; }
internal abstract void UnlockAccount(AuthenticablePrincipal p);
public ClaimsPrincipal Authenticate(string upn) { AuthenticablePrincipal authenticablePrincipal = localIdentityProviderLogic.Authenticate(upn); return(ConstructClaimsPrincipal(authenticablePrincipal, devAuthBypass)); }