LDAPNodeDataService.java 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  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.svc.node;
  21. import com.novell.ldapchai.ChaiUser;
  22. import com.novell.ldapchai.exception.ChaiException;
  23. import lombok.Value;
  24. import password.pwm.PwmDomain;
  25. import password.pwm.bean.ProfileID;
  26. import password.pwm.bean.UserIdentity;
  27. import password.pwm.config.PwmSetting;
  28. import password.pwm.config.profile.LdapProfile;
  29. import password.pwm.error.ErrorInformation;
  30. import password.pwm.error.PwmError;
  31. import password.pwm.error.PwmUnrecoverableException;
  32. import password.pwm.util.java.LazySupplier;
  33. import password.pwm.util.json.JsonFactory;
  34. import password.pwm.util.java.StringUtil;
  35. import password.pwm.util.java.TimeDuration;
  36. import password.pwm.util.logging.PwmLogger;
  37. import java.util.LinkedHashMap;
  38. import java.util.Map;
  39. import java.util.Objects;
  40. import java.util.Set;
  41. class LDAPNodeDataService implements NodeDataServiceProvider
  42. {
  43. private static final PwmLogger LOGGER = PwmLogger.forClass( LDAPNodeDataService.class );
  44. private final PwmDomain pwmDomain;
  45. private static final String VALUE_PREFIX = "0006#.#.#";
  46. private final NodeService nodeService;
  47. private final LazySupplier.CheckedSupplier<LDAPHelper, PwmUnrecoverableException> ldapHelperSupplier;
  48. LDAPNodeDataService( final NodeService nodeService, final PwmDomain pwmDomain )
  49. throws PwmUnrecoverableException
  50. {
  51. this.nodeService = nodeService;
  52. this.pwmDomain = Objects.requireNonNull( pwmDomain );
  53. final LdapProfile ldapProfile = pwmDomain.getConfig().getDefaultLdapProfile();
  54. final String testUser = ldapProfile.readSettingAsString( PwmSetting.LDAP_TEST_USER_DN );
  55. if ( StringUtil.isEmpty( testUser ) )
  56. {
  57. final String msg = "ldap node service requires that setting "
  58. + PwmSetting.LDAP_TEST_USER_DN.toMenuLocationDebug( ldapProfile.getId(), null )
  59. + " is configured";
  60. throw PwmUnrecoverableException.newException( PwmError.ERROR_NODE_SERVICE_ERROR, msg );
  61. }
  62. ldapHelperSupplier = LazySupplier.checked( () -> LDAPHelper.createLDAPHelper( nodeService, pwmDomain ) );
  63. }
  64. @Override
  65. public Map<String, StoredNodeData> readStoredData( ) throws PwmUnrecoverableException
  66. {
  67. final Map<String, StoredNodeData> returnData = new LinkedHashMap<>( );
  68. final LDAPHelper ldapHelper = ldapHelperSupplier.call();
  69. try
  70. {
  71. final Set<String> values = ldapHelper.getChaiUser().readMultiStringAttribute( ldapHelper.getAttr() );
  72. for ( final String value : values )
  73. {
  74. if ( value.startsWith( VALUE_PREFIX ) )
  75. {
  76. final String rawValue = value.substring( VALUE_PREFIX.length() );
  77. final StoredNodeData storedNodeData = JsonFactory.get().deserialize( rawValue, StoredNodeData.class );
  78. returnData.put( storedNodeData.getInstanceID(), storedNodeData );
  79. }
  80. }
  81. }
  82. catch ( final ChaiException e )
  83. {
  84. throw new PwmUnrecoverableException( PwmError.ERROR_LDAP_DATA_ERROR, "error reading node service data "
  85. + ldapHelper.debugInfo() + ", error: " + e.getMessage() );
  86. }
  87. return returnData;
  88. }
  89. @Override
  90. public void writeNodeStatus( final StoredNodeData storedNodeData ) throws PwmUnrecoverableException
  91. {
  92. final Map<String, StoredNodeData> currentServerData = readStoredData();
  93. final StoredNodeData removeNode = currentServerData.get( storedNodeData.getInstanceID() );
  94. final LDAPHelper ldapHelper = ldapHelperSupplier.call();
  95. final String newRawValue = VALUE_PREFIX + JsonFactory.get().serialize( storedNodeData );
  96. try
  97. {
  98. if ( removeNode != null )
  99. {
  100. final String oldRawValue = VALUE_PREFIX + JsonFactory.get().serialize( removeNode );
  101. ldapHelper.getChaiUser().replaceAttribute( ldapHelper.getAttr(), oldRawValue, newRawValue );
  102. }
  103. else
  104. {
  105. ldapHelper.getChaiUser().addAttribute( ldapHelper.getAttr(), newRawValue );
  106. }
  107. }
  108. catch ( final ChaiException e )
  109. {
  110. throw new PwmUnrecoverableException( PwmError.ERROR_LDAP_DATA_ERROR, "error writing node service data "
  111. + ldapHelper.debugInfo() + ", error: " + e.getMessage() );
  112. }
  113. }
  114. @Override
  115. public int purgeOutdatedNodes( final TimeDuration maxNodeAge ) throws PwmUnrecoverableException
  116. {
  117. final LDAPHelper ldapHelper = ldapHelperSupplier.call();
  118. int nodesPurged = 0;
  119. final Map<String, StoredNodeData> nodeDatas = readStoredData();
  120. for ( final StoredNodeData storedNodeData : nodeDatas.values() )
  121. {
  122. final TimeDuration recordAge = TimeDuration.fromCurrent( storedNodeData.getTimestamp() );
  123. final String instanceID = storedNodeData.getInstanceID();
  124. if ( recordAge.isLongerThan( maxNodeAge ) )
  125. {
  126. // purge outdated records
  127. LOGGER.debug( () -> "purging outdated node reference to instanceID '" + instanceID + "'" );
  128. try
  129. {
  130. final String oldRawValue = VALUE_PREFIX + JsonFactory.get().serialize( storedNodeData );
  131. ldapHelper.getChaiUser().deleteAttribute( ldapHelper.getAttr(), oldRawValue );
  132. nodesPurged++;
  133. }
  134. catch ( final ChaiException e )
  135. {
  136. throw new PwmUnrecoverableException( PwmError.ERROR_LDAP_DATA_ERROR, "error purging node service data "
  137. + ldapHelper.debugInfo() + ", error: " + e.getMessage() );
  138. }
  139. }
  140. }
  141. return nodesPurged;
  142. }
  143. @Value
  144. private static class LDAPHelper
  145. {
  146. private final NodeService nodeService;
  147. private final PwmDomain pwmDomain;
  148. private final UserIdentity userIdentity;
  149. private final ChaiUser chaiUser;
  150. private final String attr;
  151. private LDAPHelper( final NodeService nodeService, final PwmDomain pwmDomain )
  152. throws PwmUnrecoverableException
  153. {
  154. this.nodeService = nodeService;
  155. this.pwmDomain = pwmDomain;
  156. final ProfileID ldapProfileID = pwmDomain.getConfig().getDefaultLdapProfile().getId();
  157. userIdentity = pwmDomain.getConfig().getDefaultLdapProfile().getTestUser( nodeService.getSessionLabel(), pwmDomain )
  158. .orElseThrow( () ->
  159. {
  160. final String errorMsg = "a test user is not configured for ldap profile '" + ldapProfileID + "'";
  161. final ErrorInformation errorInformation = new ErrorInformation( PwmError.CONFIG_FORMAT_ERROR, errorMsg );
  162. return new PwmUnrecoverableException( errorInformation );
  163. } );
  164. chaiUser = pwmDomain.getProxiedChaiUser( nodeService.getSessionLabel(), userIdentity );
  165. attr = userIdentity.getLdapProfile( pwmDomain.getPwmApplication().getConfig() ).readSettingAsString( PwmSetting.LDAP_ATTRIBUTE_PWNOTIFY );
  166. }
  167. static LDAPHelper createLDAPHelper( final NodeService nodeService, final PwmDomain pwmDomain ) throws PwmUnrecoverableException
  168. {
  169. return new LDAPHelper( nodeService, pwmDomain );
  170. }
  171. String debugInfo()
  172. {
  173. return "user '" + this.userIdentity.toDisplayString() + "' attribute '" + attr + "'";
  174. }
  175. }
  176. }