UserIdentity.java 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243
  1. /*
  2. * Password Management Servlets (PWM)
  3. * http://www.pwm-project.org
  4. *
  5. * Copyright (c) 2006-2009 Novell, Inc.
  6. * Copyright (c) 2009-2021 The PWM Project
  7. *
  8. * Licensed under the Apache License, Version 2.0 (the "License");
  9. * you may not use this file except in compliance with the License.
  10. * You may obtain a copy of the License at
  11. *
  12. * http://www.apache.org/licenses/LICENSE-2.0
  13. *
  14. * Unless required by applicable law or agreed to in writing, software
  15. * distributed under the License is distributed on an "AS IS" BASIS,
  16. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  17. * See the License for the specific language governing permissions and
  18. * limitations under the License.
  19. */
  20. package password.pwm.bean;
  21. import com.novell.ldapchai.ChaiUser;
  22. import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
  23. import org.jetbrains.annotations.NotNull;
  24. import password.pwm.PwmApplication;
  25. import password.pwm.PwmDomain;
  26. import password.pwm.config.AppConfig;
  27. import password.pwm.config.profile.LdapProfile;
  28. import password.pwm.error.ErrorInformation;
  29. import password.pwm.error.PwmError;
  30. import password.pwm.error.PwmUnrecoverableException;
  31. import password.pwm.util.java.EnumUtil;
  32. import password.pwm.util.java.JavaHelper;
  33. import password.pwm.util.json.JsonFactory;
  34. import password.pwm.util.logging.PwmLogger;
  35. import java.io.Serializable;
  36. import java.util.Comparator;
  37. import java.util.Objects;
  38. import java.util.StringTokenizer;
  39. @SuppressFBWarnings( "SE_TRANSIENT_FIELD_NOT_RESTORED" )
  40. public class UserIdentity implements Serializable, Comparable<UserIdentity>
  41. {
  42. private static final PwmLogger LOGGER = PwmLogger.forClass( UserIdentity.class );
  43. private static final long serialVersionUID = 1L;
  44. private static final String DELIM_SEPARATOR = "|";
  45. private static final Comparator<UserIdentity> COMPARATOR = Comparator.comparing(
  46. UserIdentity::getDomainID,
  47. Comparator.nullsLast( Comparator.naturalOrder() ) )
  48. .thenComparing(
  49. UserIdentity::getLdapProfileID,
  50. ProfileID.comparator()
  51. )
  52. .thenComparing(
  53. UserIdentity::getDomainID,
  54. DomainID.comparator() );
  55. private transient boolean canonical;
  56. private final String userDN;
  57. private final ProfileID ldapProfile;
  58. private final DomainID domainID;
  59. public enum Flag
  60. {
  61. PreCanonicalized,
  62. }
  63. private UserIdentity( final String userDN, final ProfileID ldapProfile, final DomainID domainID )
  64. {
  65. this.userDN = JavaHelper.requireNonEmpty( userDN, "UserIdentity: userDN value cannot be empty" );
  66. this.ldapProfile = Objects.requireNonNull( ldapProfile, "UserIdentity: ldapProfile value cannot be empty" );
  67. this.domainID = Objects.requireNonNull( domainID );
  68. }
  69. public UserIdentity( final String userDN, final ProfileID ldapProfile, final DomainID domainID, final boolean canonical )
  70. {
  71. this( userDN, ldapProfile, domainID );
  72. this.canonical = canonical;
  73. }
  74. public static UserIdentity create(
  75. final String userDN,
  76. final ProfileID ldapProfile,
  77. final DomainID domainID,
  78. final Flag... flags
  79. )
  80. {
  81. final boolean canonical = EnumUtil.enumArrayContainsValue( flags, Flag.PreCanonicalized );
  82. return new UserIdentity( userDN, ldapProfile, domainID, canonical );
  83. }
  84. public String getUserDN( )
  85. {
  86. return userDN;
  87. }
  88. public DomainID getDomainID()
  89. {
  90. return domainID;
  91. }
  92. public ProfileID getLdapProfileID( )
  93. {
  94. return ldapProfile;
  95. }
  96. public LdapProfile getLdapProfile( final AppConfig appConfig )
  97. {
  98. Objects.requireNonNull( appConfig );
  99. final LdapProfile ldapProfile = appConfig.getDomainConfigs().get( domainID ).getLdapProfiles().get( this.getLdapProfileID() );
  100. if ( ldapProfile == null )
  101. {
  102. throw new IllegalStateException( "bogus ldapProfileID on userIdentity: " + this.getLdapProfileID() );
  103. }
  104. return ldapProfile;
  105. }
  106. public String toString( )
  107. {
  108. return toDisplayString();
  109. }
  110. public String toDelimitedKey( )
  111. {
  112. return JsonFactory.get().serialize( this );
  113. }
  114. public String toDisplayString( )
  115. {
  116. return "[" + this.getDomainID() + "]"
  117. + " " + this.getUserDN()
  118. + " (" + this.getLdapProfileID().stringValue() + ")";
  119. }
  120. public static UserIdentity fromDelimitedKey( final SessionLabel sessionLabel, final String key )
  121. throws PwmUnrecoverableException
  122. {
  123. JavaHelper.requireNonEmpty( key );
  124. try
  125. {
  126. return JsonFactory.get().deserialize( key, UserIdentity.class );
  127. }
  128. catch ( final Exception e )
  129. {
  130. LOGGER.trace( sessionLabel, () -> "unable to deserialize UserIdentity: " + key + " using JSON method: " + e.getMessage() );
  131. }
  132. // old style
  133. final StringTokenizer st = new StringTokenizer( key, DELIM_SEPARATOR );
  134. DomainID domainID = null;
  135. if ( st.countTokens() < 2 )
  136. {
  137. final String msg = "not enough tokens while parsing delimited identity key";
  138. throw new PwmUnrecoverableException( new ErrorInformation( PwmError.ERROR_INTERNAL, msg ) );
  139. }
  140. else if ( st.countTokens() > 2 )
  141. {
  142. String domainStr = "";
  143. try
  144. {
  145. domainStr = st.nextToken();
  146. domainID = DomainID.create( domainStr );
  147. }
  148. catch ( final Exception e )
  149. {
  150. final String msg = "error decoding DomainID '" + domainStr + "' from delimited UserIdentity: " + e.getMessage();
  151. throw new PwmUnrecoverableException( new ErrorInformation( PwmError.ERROR_INTERNAL, msg ) );
  152. }
  153. }
  154. if ( st.countTokens() > 3 )
  155. {
  156. throw new PwmUnrecoverableException( new ErrorInformation( PwmError.ERROR_INTERNAL, "too many string tokens while parsing delimited identity key" ) );
  157. }
  158. final ProfileID profileID = ProfileID.create( st.nextToken() );
  159. final String userDN = st.nextToken();
  160. return create( userDN, profileID, domainID );
  161. }
  162. public boolean canonicalEquals( final SessionLabel sessionLabel, final UserIdentity otherIdentity, final PwmApplication pwmApplication )
  163. throws PwmUnrecoverableException
  164. {
  165. if ( otherIdentity == null )
  166. {
  167. return false;
  168. }
  169. final UserIdentity thisCanonicalIdentity = this.canonicalized( sessionLabel, pwmApplication );
  170. final UserIdentity otherCanonicalIdentity = otherIdentity.canonicalized( sessionLabel, pwmApplication );
  171. return thisCanonicalIdentity.equals( otherCanonicalIdentity );
  172. }
  173. @Override
  174. public boolean equals( final Object o )
  175. {
  176. if ( this == o )
  177. {
  178. return true;
  179. }
  180. if ( o == null || getClass() != o.getClass() )
  181. {
  182. return false;
  183. }
  184. final UserIdentity that = ( UserIdentity ) o;
  185. return Objects.equals( domainID, that.domainID )
  186. && Objects.equals( ldapProfile, that.ldapProfile )
  187. && Objects.equals( userDN, that.userDN );
  188. }
  189. @Override
  190. public int hashCode()
  191. {
  192. return Objects.hash( domainID, ldapProfile, userDN );
  193. }
  194. @Override
  195. public int compareTo( @NotNull final UserIdentity otherIdentity )
  196. {
  197. return COMPARATOR.compare( this, otherIdentity );
  198. }
  199. public UserIdentity canonicalized( final SessionLabel sessionLabel, final PwmApplication pwmApplication )
  200. throws PwmUnrecoverableException
  201. {
  202. if ( this.canonical )
  203. {
  204. return this;
  205. }
  206. final ChaiUser chaiUser = pwmApplication.domains().get( this.getDomainID() ).getProxiedChaiUser( sessionLabel, this );
  207. final LdapProfile ldapProfile = getLdapProfile( pwmApplication.getConfig() );
  208. final PwmDomain domain = pwmApplication.domains().get( domainID );
  209. final String userDN = ldapProfile.readCanonicalDN( sessionLabel, domain, chaiUser.getEntryDN() );
  210. return create( userDN, this.getLdapProfileID(), this.getDomainID(), Flag.PreCanonicalized );
  211. }
  212. }