PasswordAuthenticationService.cs 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. /*
  2. * Copyright (c) Contributors, http://opensimulator.org/
  3. * See CONTRIBUTORS.TXT for a full list of copyright holders.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions are met:
  7. * * Redistributions of source code must retain the above copyright
  8. * notice, this list of conditions and the following disclaimer.
  9. * * Redistributions in binary form must reproduce the above copyright
  10. * notice, this list of conditions and the following disclaimer in the
  11. * documentation and/or other materials provided with the distribution.
  12. * * Neither the name of the OpenSimulator Project nor the
  13. * names of its contributors may be used to endorse or promote products
  14. * derived from this software without specific prior written permission.
  15. *
  16. * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
  17. * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  18. * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  19. * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
  20. * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  21. * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  22. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  23. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  24. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  25. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  26. */
  27. using System;
  28. using System.Collections.Generic;
  29. using OpenMetaverse;
  30. using OpenSim.Services.Interfaces;
  31. using log4net;
  32. using Nini.Config;
  33. using System.Reflection;
  34. using OpenSim.Data;
  35. using OpenSim.Framework;
  36. using OpenSim.Framework.Console;
  37. namespace OpenSim.Services.AuthenticationService
  38. {
  39. // Generic Authentication service used for identifying
  40. // and authenticating principals.
  41. // Principals may be clients acting on users' behalf,
  42. // or any other components that need
  43. // verifiable identification.
  44. //
  45. public class PasswordAuthenticationService :
  46. AuthenticationServiceBase, IAuthenticationService
  47. {
  48. private static readonly ILog m_log =
  49. LogManager.GetLogger(
  50. MethodBase.GetCurrentMethod().DeclaringType);
  51. public PasswordAuthenticationService(IConfigSource config, IUserAccountService userService) :
  52. base(config, userService)
  53. {
  54. m_log.Debug("[AUTH SERVICE]: Started with User Account access");
  55. }
  56. public PasswordAuthenticationService(IConfigSource config) :
  57. base(config)
  58. {
  59. }
  60. public string Authenticate(UUID principalID, string password, int lifetime)
  61. {
  62. UUID realID;
  63. return Authenticate(principalID, password, lifetime, out realID);
  64. }
  65. public string Authenticate(UUID principalID, string password, int lifetime, out UUID realID)
  66. {
  67. realID = UUID.Zero;
  68. m_log.DebugFormat("[AUTH SERVICE]: Authenticating for {0}, user account service present: {1}", principalID, m_UserAccountService != null);
  69. AuthenticationData data = m_Database.Get(principalID);
  70. UserAccount user = null;
  71. if (m_UserAccountService != null)
  72. user = m_UserAccountService.GetUserAccount(UUID.Zero, principalID);
  73. if (data == null || data.Data == null)
  74. {
  75. m_log.DebugFormat("[AUTH SERVICE]: PrincipalID {0} or its data not found", principalID);
  76. return String.Empty;
  77. }
  78. if (!data.Data.ContainsKey("passwordHash") ||
  79. !data.Data.ContainsKey("passwordSalt"))
  80. {
  81. return String.Empty;
  82. }
  83. string hashed = Util.Md5Hash(password + ":" +
  84. data.Data["passwordSalt"].ToString());
  85. // m_log.DebugFormat("[PASS AUTH]: got {0}; hashed = {1}; stored = {2}", password, hashed, data.Data["passwordHash"].ToString());
  86. if (data.Data["passwordHash"].ToString() == hashed)
  87. {
  88. return GetToken(principalID, lifetime);
  89. }
  90. if (user == null)
  91. {
  92. m_log.DebugFormat("[PASS AUTH]: No user record for {0}", principalID);
  93. return String.Empty;
  94. }
  95. int impersonateFlag = 1 << 6;
  96. if ((user.UserFlags & impersonateFlag) == 0)
  97. return String.Empty;
  98. m_log.DebugFormat("[PASS AUTH]: Attempting impersonation");
  99. List<UserAccount> accounts = m_UserAccountService.GetUserAccountsWhere(UUID.Zero, "UserLevel >= 200");
  100. if (accounts == null || accounts.Count == 0)
  101. {
  102. m_log.DebugFormat("[PASS AUTH]: No suitable gods found");
  103. return String.Empty;
  104. }
  105. foreach (UserAccount a in accounts)
  106. {
  107. data = m_Database.Get(a.PrincipalID);
  108. if (data == null || data.Data == null ||
  109. !data.Data.ContainsKey("passwordHash") ||
  110. !data.Data.ContainsKey("passwordSalt"))
  111. {
  112. m_log.DebugFormat("[PASS AUTH]: {0} {1} has no suitable password set", a.FirstName, a.LastName);
  113. continue;
  114. }
  115. // m_log.DebugFormat("[PASS AUTH]: Trying {0}", data.PrincipalID);
  116. hashed = Util.Md5Hash(password + ":" +
  117. data.Data["passwordSalt"].ToString());
  118. if (data.Data["passwordHash"].ToString() == hashed)
  119. {
  120. m_log.DebugFormat("[PASS AUTH]: {0} {1} impersonating {2}, proceeding with login", a.FirstName, a.LastName, principalID);
  121. realID = a.PrincipalID;
  122. return GetToken(principalID, lifetime);
  123. }
  124. else
  125. {
  126. m_log.DebugFormat(
  127. "[AUTH SERVICE]: Salted hash {0} of given password did not match salted hash of {1} for PrincipalID {2}. Authentication failure.",
  128. hashed, data.Data["passwordHash"], data.PrincipalID);
  129. }
  130. }
  131. m_log.DebugFormat("[PASS AUTH]: Impersonation of {0} failed", principalID);
  132. return String.Empty;
  133. }
  134. }
  135. }