/// <summary> /// Gets the login status for the specified user. /// </summary> /// <param name="connection">Ldap connection to use to get the status.</param> /// <param name="status">User information.</param> private void GetUserStatus(bool proxyUser, LdapConnection connection, Simias.Authentication.Status status) { if (connection != null) { readADDomainInfo(connection); // Get the search attributes for login status. string[] searchAttributes = { "userAccountControl", "accountExpires", "pwdLastSet", "lockoutTime" }; LdapEntry ldapEntry = connection.Read(status.DistinguishedUserName, searchAttributes); if (ldapEntry != null) { // If the account has been disabled or the account has expired // the bind will fail and we'll come through on the proxy user // connection so there is no reason for the extra checking on // a successful bind in the context of the actual user. if (proxyUser == true && AccountDisabled(ldapEntry)) { status.statusCode = SCodes.AccountDisabled; } else if (proxyUser == true && AccountExpired(ldapEntry)) { status.statusCode = SCodes.AccountDisabled; } else if (proxyUser == true && AccountLockedOut(ldapEntry)) { status.statusCode = SCodes.AccountLockout; } else { if (IsPasswordRequired(ldapEntry)) { if (CanUserChangePassword(ldapEntry)) { int daysUntilExpired; if (IsPasswordExpired(ldapEntry, out daysUntilExpired)) { status.statusCode = SCodes.AccountLockout; } else if (status.statusCode.Equals(SCodes.Success)) { status.DaysUntilPasswordExpires = daysUntilExpired; } } } } } else { status.statusCode = SCodes.InternalException; status.ExceptionMessage = "Failed reading LDAP attributes"; } } }
/// <summary> /// Method to verify a user's password /// </summary> /// <param name="Username">User to verify the password against</param> /// <param name="Password">Password to verify</param> /// <param name="status">Structure used to pass additional information back to the user.</param> /// <returns>true - Valid password, false Invalid password</returns> static public bool VerifyPassword(string Username, string Password, Simias.Authentication.Status status) { if (User.provider != null) { return(User.provider.VerifyPassword(Username, Password, status)); } return(false); }
/// <summary> /// Method to verify a user's password /// </summary> /// <param name="Username">User to verify the password against</param> /// <param name="Password">Password to verify</param> /// <param name="status">Structure used to pass additional information back to the user.</param> /// <returns>true - Valid password, false Invalid password</returns> public bool VerifyPassword(string Username, string Password, Simias.Authentication.Status status) { bool result; try { Member member = domain.GetMemberByName(Username); if (member != null) { Property pwd = member.Properties.GetSingleProperty(InternalUser.pwdProperty); if (pwd != null && (pwd.Value as string == HashPassword(Password))) { status.UserID = member.UserID; status.statusCode = SCodes.Success; result = true; } else { status.statusCode = SCodes.InvalidCredentials; result = false; } } else { log.Debug("failed to find user: {0}", Username); status.statusCode = SCodes.UnknownUser; result = false; } } catch (Exception e1) { log.Error(e1.Message); log.Error(e1.StackTrace); status.statusCode = SCodes.InternalException; status.ExceptionMessage = e1.Message; result = false; } return(result); }
public Simias.Authentication.Status Authenticate( string collectionID ) { HttpWebResponse response = null; Simias.Authentication.Status status = new Simias.Authentication.Status( SCodes.Unknown ); Store store = Store.GetStore(); Simias.Storage.Domain domain = store.GetDomain( GaimDomain.ID ); Simias.Storage.Member member = domain.GetCurrentMember(); GaimDomainProvider gaimDomainProvider = new GaimDomainProvider(); Uri remoteUri = gaimDomainProvider.ResolveLocation( GaimDomain.ID, collectionID ); if ( remoteUri == null ) { status.statusCode = SCodes.UnknownDomain; return status; } Uri loginUri = new Uri( remoteUri.ToString() + "/Login.ashx" ); HttpWebRequest request = WebRequest.Create( loginUri ) as HttpWebRequest; WebState webState = new WebState( GaimDomain.ID ); webState.InitializeWebRequest( request, GaimDomain.ID ); request.Headers.Add( Simias.Security.Web.AuthenticationService.Login.DomainIDHeader, GaimDomain.ID ); request.Headers.Add( "gaim-member", member.UserID ); request.Method = "POST"; request.ContentLength = 0; try { request.GetRequestStream().Close(); response = request.GetResponse() as HttpWebResponse; if ( response != null ) { status.statusCode = SCodes.Success; } } catch(WebException webEx) { response = webEx.Response as HttpWebResponse; if (response != null) { log.Debug( response.StatusCode.ToString() ); if ( response.StatusCode == System.Net.HttpStatusCode.Unauthorized ) { string oneTimeChallenge = response.Headers[ "gaim-secret" ]; if ( oneTimeChallenge != null && oneTimeChallenge != "" ) { HttpWebRequest request2 = WebRequest.Create( loginUri ) as HttpWebRequest; WebState webState2 = new WebState( GaimDomain.ID ); webState2.InitializeWebRequest( request2, GaimDomain.ID ); request2.CookieContainer.Add(response.Cookies); request2.Headers.Add( Simias.Security.Web.AuthenticationService.Login.DomainIDHeader, GaimDomain.ID ); request2.Headers.Add( "gaim-member", member.UserID ); try { RSACryptoServiceProvider credential = GaimDomain.GetCredential(); if (credential != null) { byte[] oneTime = Convert.FromBase64String( oneTimeChallenge ); byte[] decryptedText = credential.Decrypt( oneTime, false ); request2.Headers.Add( "gaim-secret", Convert.ToBase64String( decryptedText ) ); } else { log.Debug( "Couldn't get our own RSACryptoServiceProvider (our private key)" ); status.statusCode = SCodes.Unknown; return status; } } catch( Exception enc ) { log.Debug( "Error decrypting one time secret." ); log.Debug( enc.Message ); log.Debug( enc.StackTrace ); } request2.Method = "POST"; request2.ContentLength = 0; try { request2.GetRequestStream().Close(); response = request2.GetResponse() as HttpWebResponse; if ( response != null ) { status.statusCode = SCodes.Success; } } catch( WebException webEx2 ) { log.Debug( "WebException: " + webEx2.Status.ToString() ); log.Debug( webEx2.Message ); log.Debug( webEx2.StackTrace ); } catch( Exception e2 ) { log.Debug( "Other exception" ); log.Debug( e2.Message ); log.Debug( e2.StackTrace ); } } else { log.Debug( "One Time Challenge NOT present"); } } } else { log.Debug( "Couldn't get the HttpWebResponse" ); log.Debug(webEx.Message); log.Debug(webEx.StackTrace); } } catch(Exception ex) { log.Debug( "Catch-all Exception" ); log.Debug(ex.Message); log.Debug(ex.StackTrace); } return status; }
/// <summary> /// Method to verify a user's password /// </summary> /// <param name="Username">User to verify the password against</param> /// <param name="Password">Password to verify</param> /// <param name="status">Structure used to pass additional information back to the user.</param> /// <returns>true - Valid password, false Invalid password</returns> public bool VerifyPassword(string Username, string Password, Simias.Authentication.Status status) { log.Debug("VerifyPassword for: " + Username); LdapConnection conn = null; LdapConnection proxyConnection = null; // Get the distinguished name and member(user) id from the // simias store rather than the ldap server if (GetUserDN(Username, out status.DistinguishedUserName, out status.UserID) == false) { log.Debug("failed to get the user's distinguished name"); status.statusCode = SCodes.UnknownUser; return(false); } bool doNotCheckStatus = false; try { conn = new LdapConnection(); conn.SecureSocketLayer = ldapSettings.SSL; conn.UserDefinedServerCertValidationDelegate += new CertificateValidationCallback(SSLHandler); conn.Connect(ldapSettings.Host, ldapSettings.Port); conn.Bind(status.DistinguishedUserName, Password); if (conn.AuthenticationDN == null) { doNotCheckStatus = true; throw new LdapException("Anonymous bind is not allowed", LdapException.INAPPROPRIATE_AUTHENTICATION, "Anonymous bind is not allowed"); } status.statusCode = SCodes.Success; GetUserStatus(false, conn, status); return(true); } catch (LdapException e) { log.Error("LdapError:" + e.LdapErrorMessage); log.Error("Error:" + e.Message); log.Error("DN:" + status.DistinguishedUserName); switch (e.ResultCode) { case LdapException.INVALID_CREDENTIALS: status.statusCode = SCodes.InvalidCredentials; break; case LdapException.SSL_HANDSHAKE_FAILED: case LdapException.CONNECT_ERROR: if (CertFailure == true) { status.statusCode = SCodes.InvalidCertificate; } CertFailure = false; break; default: status.statusCode = SCodes.InternalException; break; } status.ExceptionMessage = e.Message; if (!doNotCheckStatus) { proxyConnection = BindProxyUser(); if (proxyConnection != null) { // GetUserStatus may change the status code GetUserStatus(true, proxyConnection, status); } } } catch (Exception e) { log.Error("Error:" + e.Message); status.statusCode = SCodes.InternalException; status.ExceptionMessage = e.Message; proxyConnection = BindProxyUser(); if (proxyConnection != null) { // GetUserStatus may change the status code GetUserStatus(true, proxyConnection, status); } } finally { if (conn != null) { // In Mono 2.0 runtime environment, first connection.Disconnect() // always throws exception(bug 449092). // First disconnect always throws "The socket is not connected" Messages. // With this try, catch only ignoring that perticular Exception try { conn.Disconnect(); } catch (Exception Ex) { if (String.Compare(Ex.Message, "The socket is not connected") != 0) { throw Ex; } else { log.Info("LdapConnection.Disconnect Exception {0} {1} ", Ex.Message, Ex.StackTrace); } } } if (proxyConnection != null) { try{ proxyConnection.Disconnect(); }catch {} } } return(false); }
/// <summary> /// Set the response headers for Http actions /// </summary> /// <param name="ctx">Context for the Http</param> /// <param name="status">Status whether authenticated or not</param> private static void SetResponseHeaders(HttpContext ctx, Simias.Authentication.Status status) { switch (status.statusCode) { case StatusCodes.Success: { if (status.DaysUntilPasswordExpires != -1) { ctx.Response.AppendHeader( DaysUntilPwdExpiresHeader, status.DaysUntilPasswordExpires.ToString()); } if (UserMoved == 1) { ctx.Response.AppendHeader( UserMovedHeader, StatusCodes.UserAlreadyMoved.ToString()); } break; } case StatusCodes.SuccessInGrace: { ctx.Response.AppendHeader( GraceTotalHeader, status.TotalGraceLogins.ToString()); ctx.Response.AppendHeader( GraceRemainingHeader, status.RemainingGraceLogins.ToString()); if (UserMoved == 1) { ctx.Response.AppendHeader( UserMovedHeader, StatusCodes.UserAlreadyMoved.ToString()); } break; } case StatusCodes.AccountDisabled: { ctx.Response.StatusCode = 401; ctx.Response.AddHeader( SimiasErrorHeader, StatusCodes.AccountDisabled.ToString()); break; } case StatusCodes.AccountLockout: { ctx.Response.StatusCode = 401; ctx.Response.AddHeader( SimiasErrorHeader, StatusCodes.AccountLockout.ToString()); break; } case StatusCodes.SimiasLoginDisabled: { ctx.Response.StatusCode = 401; ctx.Response.AddHeader( SimiasErrorHeader, StatusCodes.SimiasLoginDisabled.ToString()); break; } case StatusCodes.AmbiguousUser: { ctx.Response.StatusCode = 401; ctx.Response.AddHeader( SimiasErrorHeader, StatusCodes.AmbiguousUser.ToString()); break; } case StatusCodes.UnknownUser: { ctx.Response.StatusCode = 401; ctx.Response.AddHeader( SimiasErrorHeader, StatusCodes.UnknownUser.ToString()); break; } case StatusCodes.Unknown: { ctx.Response.StatusCode = 401; ctx.Response.AddHeader( SimiasErrorHeader, StatusCodes.Unknown.ToString()); break; } case StatusCodes.InvalidCredentials: { ctx.Response.StatusCode = 401; ctx.Response.AddHeader( SimiasErrorHeader, StatusCodes.InvalidCredentials.ToString()); break; } case StatusCodes.InvalidCertificate: { ctx.Response.StatusCode = 401; ctx.Response.AddHeader( SimiasErrorHeader, StatusCodes.InvalidCertificate.ToString()); break; } case StatusCodes.InvalidPassword: { ctx.Response.StatusCode = 401; /* * context.Response.AppendHeader( * Login.SimiasErrorHeader, * StatusCodes.InvalidPassword.ToString() ); */ break; } case StatusCodes.InternalException: { ctx.Response.StatusCode = 500; ctx.Response.AddHeader( SimiasErrorHeader, StatusCodes.InternalException.ToString()); break; } case StatusCodes.UserAlreadyMoved: { ctx.Response.AddHeader( UserMovedHeader, StatusCodes.UserAlreadyMoved.ToString()); break; } default: ctx.Response.StatusCode = 401; break; } }
/// <summary> /// Gets the login status for the specified user. /// </summary> /// <param name="connection">Ldap connection to use to get the status.</param> /// <param name="status">User information.</param> private void GetUserStatus(bool proxyUser, LdapConnection connection, Simias.Authentication.Status status) { if (connection != null) { // Get the search attributes for login status. string[] searchAttributes = { "loginDisabled", "loginExpirationTime", "loginGraceLimit", "loginGraceRemaining", "passwordAllowChange", "passwordRequired", "passwordExpirationTime" }; LdapEntry ldapEntry = connection.Read(status.DistinguishedUserName, searchAttributes); if (ldapEntry != null) { // If the account has been disabled or the account has expired // the bind will fail and we'll come through on the proxy user // connection so there is no reason for the extra checking on // a successful bind in the context of the actual user. if (proxyUser == true && LoginDisabled(ldapEntry) == true) { status.statusCode = SCodes.AccountDisabled; } else if (proxyUser == true && LoginAccountExpired(ldapEntry) == true) { status.statusCode = SCodes.AccountDisabled; } else { if (LoginIsPasswordRequired(ldapEntry) == true) { if (LoginCanUserChangePassword(ldapEntry) == true) { if (LoginPasswordExpired(ldapEntry) == true) { status.TotalGraceLogins = LoginGraceLimit(ldapEntry); status.RemainingGraceLogins = LoginGraceRemaining(ldapEntry); if (status.statusCode == SCodes.Success && (status.TotalGraceLogins == -1 || status.RemainingGraceLogins >= 0)) { status.statusCode = SCodes.SuccessInGrace; } else { status.statusCode = SCodes.AccountLockout; } } } } } } else { status.statusCode = SCodes.InternalException; status.ExceptionMessage = "Failed reading LDAP attributes"; } } }