Selaa lähdekoodia

pwnotify changes

jrivard@gmail.com 6 vuotta sitten
vanhempi
commit
ec539abf8d

+ 7 - 1
server/src/main/java/password/pwm/config/PwmSetting.java

@@ -97,6 +97,8 @@ public enum PwmSetting
             "pwm.appProperty.overrides", PwmSettingSyntax.STRING_ARRAY, PwmSettingCategory.GENERAL ),
 
     // clustering
+    CLUSTER_ENABLED(
+            "cluster.enable", PwmSettingSyntax.BOOLEAN, PwmSettingCategory.CLUSTERING ),
     CLUSTER_STORAGE_MODE(
             "cluster.storageMode", PwmSettingSyntax.SELECT, PwmSettingCategory.CLUSTERING ),
     SECURITY_LOGIN_SESSION_MODE(
@@ -280,12 +282,13 @@ public enum PwmSetting
             "peopleSearch.orgChart.workforceIdAttribute", PwmSettingSyntax.STRING, PwmSettingCategory.LDAP_ATTRIBUTES ),
     LDAP_ATTRIBUTE_LANGUAGE(
             "ldap.user.language.attribute", PwmSettingSyntax.STRING, PwmSettingCategory.LDAP_ATTRIBUTES ),
+    LDAP_ATTRIBUTE_PWNOTIFY(
+            "ldap.user.pwNotify.attribute", PwmSettingSyntax.STRING, PwmSettingCategory.LDAP_ATTRIBUTES ),
     LDAP_AUTO_SET_LANGUAGE_VALUE(
             "ldap.user.language.autoSet", PwmSettingSyntax.SELECT, PwmSettingCategory.LDAP_ATTRIBUTES ),
     AUTO_ADD_OBJECT_CLASSES(
             "ldap.addObjectClasses", PwmSettingSyntax.STRING_ARRAY, PwmSettingCategory.LDAP_ATTRIBUTES ),
 
-
     // ldap global settings
     LDAP_PROFILE_LIST(
             "ldap.profile.list", PwmSettingSyntax.PROFILE, PwmSettingCategory.INTERNAL ),
@@ -1110,6 +1113,9 @@ public enum PwmSetting
     // pw expiry notice
     PW_EXPY_NOTIFY_ENABLE(
             "pwNotify.enable", PwmSettingSyntax.BOOLEAN, PwmSettingCategory.PW_EXP_NOTIFY ),
+    PW_EXPY_NOTIFY_STORAGE_MODE(
+            "pwNotify.storageMode", PwmSettingSyntax.SELECT, PwmSettingCategory.PW_EXP_NOTIFY ),
+
     PW_EXPY_NOTIFY_PERMISSION(
             "pwNotify.queryString", PwmSettingSyntax.USER_PERMISSION, PwmSettingCategory.PW_EXP_NOTIFY ),
     PW_EXPY_NOTIFY_INTERVAL(

+ 2 - 0
server/src/main/java/password/pwm/error/PwmError.java

@@ -307,6 +307,8 @@ public enum PwmError
             5093, "Error_ClusterServiceError", null ),
     ERROR_WORDLIST_IMPORT_ERROR(
             5094, "Error_WordlistImportError", null ),
+    ERROR_PWNOTIFY_SERVICE_ERROR(
+            5095, "Error_PwNotifyServiceError", null ),
 
     ERROR_REMOTE_ERROR_VALUE(
             6000, "Error_RemoteErrorValue", null, ErrorFlag.Permanent ),

+ 1 - 0
server/src/main/java/password/pwm/health/HealthMessage.java

@@ -88,6 +88,7 @@ public enum HealthMessage
     LocalDBLogger_NOTOPEN( HealthStatus.CAUTION, HealthTopic.LocalDB ),
     LocalDBLogger_HighRecordCount( HealthStatus.CAUTION, HealthTopic.LocalDB ),
     LocalDBLogger_OldRecordPresent( HealthStatus.CAUTION, HealthTopic.LocalDB ),
+    ServiceClosed( HealthStatus.CAUTION, HealthTopic.Application ),
     ServiceClosed_LocalDBUnavail( HealthStatus.CAUTION, HealthTopic.Application ),
     ServiceClosed_AppReadOnly( HealthStatus.CAUTION, HealthTopic.Application ),
     SMS_SendFailure( HealthStatus.WARN, HealthTopic.SMS ),

+ 78 - 0
server/src/main/java/password/pwm/svc/AbstractPwmService.java

@@ -0,0 +1,78 @@
+/*
+ * Password Management Servlets (PWM)
+ * http://www.pwm-project.org
+ *
+ * Copyright (c) 2006-2009 Novell, Inc.
+ * Copyright (c) 2009-2018 The PWM Project
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+package password.pwm.svc;
+
+import password.pwm.error.ErrorInformation;
+import password.pwm.health.HealthMessage;
+import password.pwm.health.HealthRecord;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+public abstract class AbstractPwmService
+{
+    private PwmService.STATUS status = PwmService.STATUS.CLOSED;
+    private ErrorInformation startupError;
+
+    public final PwmService.STATUS status()
+    {
+        return status;
+    }
+
+    protected void setStatus( final PwmService.STATUS status )
+    {
+        this.status = status;
+    }
+
+    protected void setStartupError( final ErrorInformation startupError )
+    {
+        this.startupError = startupError;
+    }
+
+    protected ErrorInformation getStartupError()
+    {
+        return startupError;
+    }
+    public final List<HealthRecord> healthCheck( )
+    {
+        if ( status != PwmService.STATUS.OPEN )
+        {
+            return Collections.emptyList();
+        }
+
+        final List<HealthRecord> returnRecords = new ArrayList<>(  );
+
+        final ErrorInformation startupError = this.startupError;
+        if ( startupError != null )
+        {
+            returnRecords.add( HealthRecord.forMessage( HealthMessage.ServiceClosed, startupError.toDebugStr() ) );
+        }
+
+        returnRecords.addAll( serviceHealthCheck() );
+
+        return returnRecords;
+    }
+
+    protected abstract List<HealthRecord> serviceHealthCheck();
+}

+ 6 - 0
server/src/main/java/password/pwm/svc/cluster/ClusterService.java

@@ -66,6 +66,12 @@ public class ClusterService implements PwmService
         status = STATUS.OPENING;
         this.pwmApplication = pwmApplication;
 
+        final boolean serviceEnabled = pwmApplication.getConfig().readSettingAsBoolean( PwmSetting.CLUSTER_ENABLED );
+        if ( !serviceEnabled )
+        {
+            status = STATUS.CLOSED;
+            return;
+        }
 
         try
         {

+ 7 - 1
server/src/main/java/password/pwm/svc/pwnotify/PwNotifyDbStorageService.java

@@ -42,9 +42,15 @@ class PwNotifyDbStorageService implements PwNotifyStorageService
     private static final DatabaseTable TABLE = DatabaseTable.PW_NOTIFY;
     private final PwmApplication pwmApplication;
 
-    PwNotifyDbStorageService( final PwmApplication pwmApplication )
+    PwNotifyDbStorageService( final PwmApplication pwmApplication ) throws PwmUnrecoverableException
     {
         this.pwmApplication = pwmApplication;
+
+        if ( !pwmApplication.getConfig().hasDbConfigured() )
+        {
+            final String msg = "DB storage type selected, but remote DB is not configured.";
+            throw PwmUnrecoverableException.newException( PwmError.ERROR_CLUSTER_SERVICE_ERROR, msg );
+        }
     }
 
     @Override

+ 0 - 1
server/src/main/java/password/pwm/svc/pwnotify/PwNotifyEngine.java

@@ -385,5 +385,4 @@ public class PwNotifyEngine
         threadPoolExecutor.allowCoreThreadTimeOut( true );
         return threadPoolExecutor;
     }
-
 }

+ 34 - 7
server/src/main/java/password/pwm/svc/pwnotify/PwNotifyLdapStorageService.java

@@ -27,8 +27,10 @@ import com.novell.ldapchai.exception.ChaiOperationException;
 import com.novell.ldapchai.exception.ChaiUnavailableException;
 import com.novell.ldapchai.util.ConfigObjectRecord;
 import password.pwm.PwmApplication;
+import password.pwm.PwmConstants;
 import password.pwm.bean.SessionLabel;
 import password.pwm.bean.UserIdentity;
+import password.pwm.config.PwmSetting;
 import password.pwm.config.profile.LdapProfile;
 import password.pwm.error.ErrorInformation;
 import password.pwm.error.PwmError;
@@ -60,9 +62,31 @@ class PwNotifyLdapStorageService implements PwNotifyStorageService
     }
 
     PwNotifyLdapStorageService( final PwmApplication pwmApplication, final PwNotifySettings settings )
+            throws PwmUnrecoverableException
     {
         this.pwmApplication = pwmApplication;
         this.settings = settings;
+
+        final UserIdentity userIdentity = pwmApplication.getConfig().getDefaultLdapProfile().getTestUser( pwmApplication );
+        if ( userIdentity == null )
+        {
+            final String msg = "LDAP storage type selected, but LDAP test user ("
+                    + PwmSetting.LDAP_TEST_USER_DN.toMenuLocationDebug( pwmApplication.getConfig().getDefaultLdapProfile().getIdentifier(), PwmConstants.DEFAULT_LOCALE )
+                    + ") not defined.";
+            throw new PwmUnrecoverableException( PwmError.ERROR_PWNOTIFY_SERVICE_ERROR, msg );
+        }
+
+        for ( final LdapProfile ldapProfile : pwmApplication.getConfig().getLdapProfiles().values() )
+        {
+            if ( StringUtil.isEmpty( ldapProfile.readSettingAsString( PwmSetting.LDAP_ATTRIBUTE_PWNOTIFY ) ) )
+            {
+                final String msg = "LDAP storage type selected, but setting '"
+                        + PwmSetting.LDAP_ATTRIBUTE_PWNOTIFY.toMenuLocationDebug( ldapProfile.getIdentifier(), PwmConstants.DEFAULT_LOCALE )
+                        + " is not configured ";
+                throw new PwmUnrecoverableException( PwmError.ERROR_PWNOTIFY_SERVICE_ERROR, msg );
+            }
+        }
+
     }
 
     @Override
@@ -96,7 +120,7 @@ class PwNotifyLdapStorageService implements PwNotifyStorageService
         }
         catch ( ChaiOperationException e )
         {
-            final String msg = "error writing user pwNotifyStatus attribute '" + settings.getLdapUserAttribute() + ", error: " + e.getMessage();
+            final String msg = "error writing user pwNotifyStatus attribute '" + getLdapUserAttribute( userIdentity ) + ", error: " + e.getMessage();
             final ErrorInformation errorInformation = new ErrorInformation( PwmError.ERROR_LDAP_DATA_ERROR, msg );
             throw new PwmUnrecoverableException( errorInformation );
         }
@@ -110,8 +134,7 @@ class PwNotifyLdapStorageService implements PwNotifyStorageService
     public StoredJobState readStoredJobState()
             throws PwmUnrecoverableException
     {
-        final LdapProfile ldapProfile = pwmApplication.getConfig().getDefaultLdapProfile();
-        final UserIdentity proxyUser = ldapProfile.getProxyUser( pwmApplication );
+        final UserIdentity proxyUser = pwmApplication.getConfig().getDefaultLdapProfile().getTestUser( pwmApplication );
         final ConfigObjectRecord configObjectRecord = getUserCOR( proxyUser, CoreType.ProxyUser );
         final String payload = configObjectRecord.getPayload();
 
@@ -126,8 +149,7 @@ class PwNotifyLdapStorageService implements PwNotifyStorageService
     public void writeStoredJobState( final StoredJobState storedJobState )
             throws PwmUnrecoverableException
     {
-        final LdapProfile ldapProfile = pwmApplication.getConfig().getDefaultLdapProfile();
-        final UserIdentity proxyUser = ldapProfile.getProxyUser( pwmApplication );
+        final UserIdentity proxyUser = pwmApplication.getConfig().getDefaultLdapProfile().getTestUser( pwmApplication );
         final ConfigObjectRecord configObjectRecord = getUserCOR( proxyUser, CoreType.ProxyUser );
         final String payload = JsonUtil.serialize( storedJobState );
 
@@ -137,7 +159,7 @@ class PwNotifyLdapStorageService implements PwNotifyStorageService
         }
         catch ( ChaiOperationException e )
         {
-            final String msg = "error writing user pwNotifyStatus attribute on proxy user '" + settings.getLdapUserAttribute() + ", error: " + e.getMessage();
+            final String msg = "error writing user pwNotifyStatus attribute on proxy user '" + getLdapUserAttribute( proxyUser ) + ", error: " + e.getMessage();
             final ErrorInformation errorInformation = new ErrorInformation( PwmError.ERROR_LDAP_DATA_ERROR, msg );
             throw new PwmUnrecoverableException( errorInformation );
         }
@@ -150,8 +172,13 @@ class PwNotifyLdapStorageService implements PwNotifyStorageService
     private ConfigObjectRecord getUserCOR( final UserIdentity userIdentity, final CoreType coreType )
             throws PwmUnrecoverableException
     {
-        final String userAttr = settings.getLdapUserAttribute();
+        final String userAttr = getLdapUserAttribute( userIdentity );
         final ChaiUser chaiUser = pwmApplication.getProxiedChaiUser( userIdentity );
         return ConfigObjectRecord.createNew( chaiUser, userAttr, coreType.getRecordID(), null, null );
     }
+
+    private String getLdapUserAttribute( final UserIdentity userIdentity )
+    {
+        return  userIdentity.getLdapProfile( pwmApplication.getConfig() ).readSettingAsString( PwmSetting.LDAP_ATTRIBUTE_PWNOTIFY );
+    }
 }

+ 58 - 33
server/src/main/java/password/pwm/svc/pwnotify/PwNotifyService.java

@@ -25,12 +25,14 @@ package password.pwm.svc.pwnotify;
 import password.pwm.PwmApplication;
 import password.pwm.bean.SessionLabel;
 import password.pwm.config.PwmSetting;
+import password.pwm.config.option.DataStorageMethod;
 import password.pwm.error.ErrorInformation;
 import password.pwm.error.PwmError;
 import password.pwm.error.PwmException;
 import password.pwm.error.PwmUnrecoverableException;
 import password.pwm.health.HealthMessage;
 import password.pwm.health.HealthRecord;
+import password.pwm.svc.AbstractPwmService;
 import password.pwm.svc.PwmService;
 import password.pwm.svc.stats.Statistic;
 import password.pwm.svc.stats.StatisticsManager;
@@ -47,7 +49,7 @@ import java.util.Collections;
 import java.util.List;
 import java.util.concurrent.ExecutorService;
 
-public class PwNotifyService implements PwmService
+public class PwNotifyService extends AbstractPwmService implements PwmService
 {
     private static final PwmLogger LOGGER = PwmLogger.forClass( PwNotifyService.class );
 
@@ -58,17 +60,19 @@ public class PwNotifyService implements PwmService
     private PwNotifySettings settings;
     private Instant nextExecutionTime;
     private PwNotifyStorageService storageService;
-    private ErrorInformation lastError;
-
-    @Override
-    public STATUS status( )
-    {
-        return status;
-    }
 
+    private DataStorageMethod storageMethod;
 
     public StoredJobState getJobState() throws PwmUnrecoverableException
     {
+        if ( status != STATUS.CLOSED )
+        {
+            if ( getStartupError() != null )
+            {
+                return StoredJobState.builder().lastError( getStartupError() ).build();
+            }
+        }
+
         return storageService.readStoredJobState();
     }
 
@@ -84,9 +88,9 @@ public class PwNotifyService implements PwmService
             return engine.getDebugLog();
         }
 
-        if ( lastError != null )
+        if ( getStartupError(  ) != null )
         {
-            return lastError.toDebugStr();
+            return getStartupError().toDebugStr();
         }
 
         return "";
@@ -99,22 +103,53 @@ public class PwNotifyService implements PwmService
 
         if ( !pwmApplication.getConfig().readSettingAsBoolean( PwmSetting.PW_EXPY_NOTIFY_ENABLE ) )
         {
-            status = STATUS.CLOSED;
             LOGGER.trace( SessionLabel.PWNOTIFY_SESSION_LABEL, "will remain closed, pw notify feature is not enabled" );
+            status = STATUS.CLOSED;
             return;
         }
 
-        settings = PwNotifySettings.fromConfiguration( pwmApplication.getConfig() );
-        storageService = new PwNotifyDbStorageService( pwmApplication );
-        //storageService = new PwNotifyLdapStorageService( pwmApplication, settings );
-        engine = new PwNotifyEngine( pwmApplication, storageService, () -> status == STATUS.CLOSED, null );
+        try
+        {
+            if ( pwmApplication.getClusterService() == null || pwmApplication.getClusterService().status() != STATUS.OPEN )
+            {
+                throw PwmUnrecoverableException.newException( PwmError.ERROR_PWNOTIFY_SERVICE_ERROR, "will remain closed, cluster service is not running" );
+            }
+
+            settings = PwNotifySettings.fromConfiguration( pwmApplication.getConfig() );
+            storageMethod = pwmApplication.getConfig().readSettingAsEnum( PwmSetting.PW_EXPY_NOTIFY_STORAGE_MODE, DataStorageMethod.class );
+
+            switch ( storageMethod )
+            {
+                case LDAP:
+                {
+                    storageService = new PwNotifyLdapStorageService( pwmApplication, settings );
+                }
+                break;
+
+                case DB:
+                {
+                    storageService = new PwNotifyDbStorageService( pwmApplication );
+                }
+                break;
 
-        executorService = JavaHelper.makeBackgroundExecutor( pwmApplication, this.getClass() );
+                default:
+                    JavaHelper.unhandledSwitchStatement( storageMethod );
+            }
+
+            engine = new PwNotifyEngine( pwmApplication, storageService, () -> status == STATUS.CLOSED, null );
 
-        pwmApplication.scheduleFixedRateJob( new PwNotifyJob(), executorService, TimeDuration.MINUTE, TimeDuration.MINUTE );
+            executorService = JavaHelper.makeBackgroundExecutor( pwmApplication, this.getClass() );
 
-        status = STATUS.OPEN;
+            pwmApplication.scheduleFixedRateJob( new PwNotifyJob(), executorService, TimeDuration.MINUTE, TimeDuration.MINUTE );
 
+            status = STATUS.OPEN;
+        }
+        catch ( PwmUnrecoverableException e )
+        {
+            status = STATUS.CLOSED;
+            LOGGER.trace( SessionLabel.PWNOTIFY_SESSION_LABEL, "will remain closed, pw notify feature is not enabled due to error: " + e.getMessage() );
+            setStartupError( e.getErrorInformation() );
+        }
     }
 
     public Instant getNextExecutionTime( )
@@ -173,19 +208,9 @@ public class PwNotifyService implements PwmService
     }
 
     @Override
-    public List<HealthRecord> healthCheck( )
+    protected List<HealthRecord> serviceHealthCheck( )
     {
-        if ( status != STATUS.OPEN )
-        {
-            return Collections.emptyList();
-        }
-
-        final List<HealthRecord> returnRecords = new ArrayList<>(  );
-
-        if ( lastError != null )
-        {
-            returnRecords.add( HealthRecord.forMessage( HealthMessage.PwNotify_Failure, lastError.toDebugStr() ) );
-        }
+        final List<HealthRecord> returnRecords = new ArrayList<>( );
 
         try
         {
@@ -210,7 +235,7 @@ public class PwNotifyService implements PwmService
     @Override
     public ServiceInfoBean serviceInfo( )
     {
-        return null;
+        return new ServiceInfoBean( Collections.singleton( storageMethod ), Collections.emptyMap() );
     }
 
     public void executeJob( )
@@ -265,7 +290,7 @@ public class PwNotifyService implements PwmService
 
         private void doJob( )
         {
-            lastError = null;
+            setStartupError( null );
             final Instant start = Instant.now();
             try
             {
@@ -303,7 +328,7 @@ public class PwNotifyService implements PwmService
                 }
                 StatisticsManager.incrementStat( pwmApplication, Statistic.PWNOTIFY_JOB_ERRORS );
                 LOGGER.debug( SessionLabel.PWNOTIFY_SESSION_LABEL, errorInformation );
-                lastError = errorInformation;
+                setStartupError( errorInformation );
             }
         }
     }

+ 0 - 4
server/src/main/java/password/pwm/svc/pwnotify/PwNotifySettings.java

@@ -46,8 +46,6 @@ class PwNotifySettings implements Serializable
     private final int batchCount;
     private final BigDecimal batchTimeMultiplier;
 
-    private final String ldapUserAttribute;
-
     static PwNotifySettings fromConfiguration( final Configuration configuration )
     {
         final PwNotifySettingsBuilder builder = PwNotifySettings.builder();
@@ -69,8 +67,6 @@ class PwNotifySettings implements Serializable
         builder.maximumSkipWindow( TimeDuration.of(
                 Long.parseLong( configuration.readAppProperty( AppProperty.PWNOTIFY_MAX_SKIP_RERUN_WINDOW_SECONDS ) ), TimeDuration.Unit.SECONDS ) );
 
-        builder.ldapUserAttribute( "carLicense" );
-
         return builder.build();
     }
 }

+ 8 - 10
server/src/main/java/password/pwm/svc/pwnotify/StoredJobState.java

@@ -22,22 +22,20 @@
 
 package password.pwm.svc.pwnotify;
 
-import lombok.AllArgsConstructor;
-import lombok.Getter;
-import lombok.NoArgsConstructor;
+import lombok.Builder;
+import lombok.Value;
 import password.pwm.error.ErrorInformation;
 
 import java.io.Serializable;
 import java.time.Instant;
 
-@Getter
-@NoArgsConstructor
-@AllArgsConstructor
+@Value
+@Builder
 public class StoredJobState implements Serializable
 {
-    private Instant lastStart = null;
-    private Instant lastCompletion = null;
-    private String serverInstance = null;
-    private ErrorInformation lastError = null;
+    private Instant lastStart;
+    private Instant lastCompletion;
+    private String serverInstance;
+    private ErrorInformation lastError;
     private boolean jobSuccess;
 }

+ 23 - 0
server/src/main/resources/password/pwm/config/PwmSetting.xml

@@ -1574,6 +1574,11 @@
             <value>28800</value>
         </default>
     </setting>
+    <setting hidden="false" key="cluster.enable" level="2">
+        <default>
+            <value>true</value>
+        </default>
+    </setting>
     <setting hidden="false" key="cluster.storageMode" level="2">
         <default>
             <value>LDAP</value>
@@ -3317,6 +3322,12 @@
             <value/>
         </default>
     </setting>
+    <setting hidden="false" key="ldap.user.pwNotify.attribute" level="1">
+        <ldapPermission actor="proxy" access="write"/>
+        <default>
+            <value/>
+        </default>
+    </setting>
     <setting hidden="false" key="ldap.user.language.autoSet" level="1">
         <ldapPermission actor="proxy" access="write"/>
         <options>
@@ -3796,6 +3807,18 @@
             <value/>
         </default>
     </setting>
+    <setting hidden="false" key="pwNotify.storageMode" level="2">
+        <default>
+            <value>LDAP</value>
+        </default>
+        <default template="DB">
+            <value>DB</value>
+        </default>
+        <options>
+            <option value="LDAP">LDAP Directory</option>
+            <option value="DB">Remote Database</option>
+        </options>
+    </setting>
     <setting hidden="false" key="pwNotify.queryString" level="1">
         <default>
             <value/>

+ 2 - 1
server/src/main/resources/password/pwm/i18n/Error.properties

@@ -164,7 +164,8 @@ Error_FileTypeIncorrect=The file type is not correct.
 Error_FileTooLarge=The file is too large.
 Error_ClusterServiceError=An error occurred with the cluster service: %1%.   Check the log files for more information.
 Error_RemoteErrorValue=Remote Error: %1%
-Error_WordlistImportError=An error occured importing the wordlist: %1%
+Error_WordlistImportError=An error occurred importing the wordlist: %1%
+Error_PwNotifyServiceError=An error occurred while running the password notify service: %1%
 
 Error_ConfigUploadSuccess=File uploaded successfully
 Error_ConfigUploadFailure=File failed to upload.

+ 1 - 0
server/src/main/resources/password/pwm/i18n/Health.properties

@@ -78,6 +78,7 @@ HealthMessage_LocalDB_CLOSED=LocalDB is CLOSED, statistics, online logging, word
 HealthMessage_LocalDBLogger_NOTOPEN=LocalDBLogger is not open, status is %1%
 HealthMessage_LocalDBLogger_HighRecordCount=LocalDBLogger event log record count of %1% records, is more than the configured maximum of %2%.  Excess records are being purged.
 HealthMessage_LocalDBLogger_OldRecordPresent=Oldest LocalDBLogger event log record is %1%, configured maximum is %2%.  Excess records are being purged.
+HealthMessage_ServiceClosed=unable to start %1% service
 HealthMessage_ServiceClosed_LocalDBUnavail=unable to start %1% service, LocalDB is not available
 HealthMessage_ServiceClosed_AppReadOnly=unable to start %1% service, application is in read-only mode
 HealthMessage_Wordlist_AutoImportFailure=Configured word list (%1%) failed to import due to error: %2% at timestamp %3%

+ 5 - 0
server/src/main/resources/password/pwm/i18n/PwmSetting.properties

@@ -267,6 +267,7 @@ Setting_Description_challenge.showConfirmation=Enable this option to show the re
 Setting_Description_challenge.token.sendMethod=Select the methods you want to use for sending the token code or new password to the user.
 Setting_Description_challenge.userAttribute=Specify the attribute to use for response storage when storing responses in an LDAP directory.
 Setting_Description_changePassword.writeAttributes=Add actions to take after a user change password event occurs.  @PwmAppName@ invokes these actions just after writing the password.  You can use macros within the action and are expanded based on the logged in user.
+Setting_Description_cluster.enable=Enable cluster module.
 Setting_Description_cluster.storageMode=Data storage system used for cluster module.  <p>If <b>LDAP</b> is selected, a test user (<a data-gotoSettingLink\="ldap.testuser.username">@PwmSettingReference\:ldap.testuser.username@</a>) must be configured and the response storage attribute (<a data-gotoSettingLink\="ldap.testuser.username">@PwmSettingReference\:ldap.testuser.username@</a>) must be writable by the proxy user.</p><p>If <b>DATABASE</b> is selected then a database must be configured and available for @PwmAppName@ to operate.</p>  
 Setting_Description_command.checkResponses.queryMatch=Controls which users are forced to setup responses.  Users that match this permission will be forced to setup responses. 
 Setting_Description_db.classname=Add the remote database JDBC driver class name.  Consult the database vendor to determine the correct class name for your database.<br/><br/><table><tr><td class\="key">Database Type</td><td class\="key">Example Class Name</td></tr><tr><td>MS-SQL</td><td>com.microsoft.sqlserver.jdbc.SQLServerDriver</td></tr><tr><td>MS-SQL using jTDS</td><td>net.sourceforge.jtds.jdbc.Driver</td></tr><tr><td>Oracle</td><td>oracle.jdbc.OracleDriver</td></tr></table><div class="footnote">The above are examples only, consult your database documentation for the proper setting value.</div>
@@ -475,6 +476,7 @@ Setting_Description_ldap.serverCerts=Import the LDAP Server Certificates.  @PwmA
 Setting_Description_ldap.serverUrls=Add a list of LDAP servers in URL format that @PwmAppName@ uses for a fail-over configuration. @PwmAppName@ uses the servers in order of appearance in this list.  If the first server is unavailable @PwmAppName@ uses the next available server in the list.  @PwmAppName@ periodically checks the first server to see if it has become available.<ul><li>For secure SSL, use the "<i>ldaps\://servername\:636</i>" format</li><li>For plain-text servers, use "<i>ldap\://serverame\:389</i>" format (not recommended)</li></ul><p>When using secure connections, the Java virtual machine must trust the directory server, either because you have manually added the public key certificate from the tree to the Java keystore or you imported the certificate into the setting <i>LDAP Server Certificates</i>.<ul><li>Do not use a non-secure connection for anything but the most basic testing purposes (Many LDAP servers reject password operations on non-secure connections)</li><li>Do not use a load-balancing device for LDAP high availability, instead use the built in LDAP server fail-over functionality</li><li>Do not use a DNS round-robin address</li><li>Avoid using the network address, use the proper fully-qualified domain name address for the server</li></ul>
 Setting_Description_ldap.testuser.username=Specify the fully qualified DN of an LDAP test user that @PwmAppName@ uses to test functionality and for access to the LDAP directory. Configure this user similar to a normal user account with normal access privileges. @PwmAppName@ periodically uses this account to perform a health check, including changing the password of the account. <br/><br/><b>Using a test user account greatly increases the system's ability to detect and alert configuration and health issues.</b><br/><br/>@PwmAppName@ tests the following functionality (if enabled) using the test user account.<ul><li>Authentication</li><li>Password policy reading</li><li>Set password</li><li>Set Challenge/Responses</li><li>Load Challenge/Responses</li></ul>
 Setting_Description_ldap.user.group.attribute=Specify an attribute on the user entry that references group entries.  The value of this attribute in the directory must be a LDAP DN.
+Setting_Description_ldap.user.pwNotify.attribute=Specify an attribute that is used by @PwmAppName@ to store data for the password expiration notification service.
 Setting_Description_ldap.user.language.attribute=Attribute that contains the language of the user in RFC1766 format. (The same format used by web browsers and the HTTP Accept-Language header.)  This value is used only for user interactions when the user does not have an active web session such as an email notification.
 Setting_Description_ldap.user.language.autoSet=When enabled, the user's effective locale for a web session will be written to the LDAP language attribute. 
 Setting_Description_ldap.username.attr=Specify the attribute @PwmAppName@ uses for the user name. If blank, @PwmAppName@ uses the LDAP Naming Attribute.  This option allows fields that display or store the <b>User Name</b> or <b>User ID</b> of a user to show something other then the LDAP Naming Attribute if appropriate.  This value must be unique for this system.
@@ -617,6 +619,7 @@ Setting_Description_pwm.securityKey=<p>Specify a Security Key used for cryptogra
 Setting_Description_pwm.seedlist.location=Specify the location of the seed list in the form of a valid URL. When @PwmAppName@ randomly generates passwords, it can generate a "friendly", random password suggestions to users.  It does this by using a "seed" word or words, and then modifying that word randomly until it is sufficiently complex and meets the configured rules computed for the user.<br/><br/>The value must be a valid URL, using the protocol "file" (local file system), "http", or "https".
 Setting_Description_pwm.selfURL=<p>The URL to this application, as seen by users. @PwmAppName@ uses the value in email macros and other user-facing communications.</p><p>The URL must use a valid fully qualified hostname. Do not use a network address.</p><p>In simple environments, the URL will be the base of the URL in the browser you are currently using to view this page, however in more complex environments the URL will typically be an upstream proxy, gateway or network device.</p><p>The URL should include the path to the base application, typically <code>/@Case:lower:[[@PwmAppName@]]@</code>.</p>
 Setting_Description_pwm.wordlist.location=Specify a word list file URL for dictionary checking to prevent users from using commonly used words as passwords.   Using word lists is an important part of password security.  Word lists are used by intruders to guess common passwords.   The default word list included contains commonly used English passwords.  <br/><br/>The first time a startup occurs with a new word list setting, it takes some time to compile the word list into a database.  See the status screen and logs for progress information.  The word list file format is one or more text files containing a single word per line, enclosed in a ZIP file.  The String <i>\!\#comment\:</i> at the beginning of a line indicates a comment. <br/><br/>The value must be a valid URL, using the protocol "file" (local file system), "http", or "https".
+Setting_Description_pwNotify.storageMode=Select storage mode used by cluster module.
 Setting_Description_pwNotify.enable=<p>Enable password expiration notification service.  Operation of this service requires that a remote database be configured.  Status of this service can be viewed on the <code>Administration -> Dashboard -> Password Notification</code> page.  The service will nominally execute once per day on the cluster master server.</p><p>If a job is missed because of an @PwmAppName@, LDAP, or database service interuption it will be run within the next 24 hours as soon as service is restored.  Running a job more than once will not result in duplicate emails sent to the user.</p>
 Setting_Description_pwNotify.queryString=Users that will receive password expiration notifications.
 Setting_Description_pwNotify.intervals=Expiration Notification Day Intervals.  The number of days before a user's password expiration before which an email notice will be set. 
@@ -778,6 +781,7 @@ Setting_Label_challenge.showConfirmation=Show Response Confirmation
 Setting_Label_challenge.token.sendMethod=Token Send Method
 Setting_Label_challenge.userAttribute=Response Storage Attribute
 Setting_Label_changePassword.writeAttributes=Post Password Change Actions
+Setting_Label_cluster.enable=Cluster Enabled
 Setting_Label_cluster.storageMode=Cluster Mode
 Setting_Label_command.checkResponses.queryMatch=Check Responses Match
 Setting_Label_db.classname=Database Class
@@ -1128,6 +1132,7 @@ Setting_Label_pwm.securityKey=Security Key
 Setting_Label_pwm.seedlist.location=Seed List File URL
 Setting_Label_pwm.selfURL=Site URL
 Setting_Label_pwm.wordlist.location=Word List File URL
+Setting_Label_pwNotify.storageMode=Storage Mode
 Setting_Label_pwNotify.enable=Enable Password Expiration Notification
 Setting_Label_pwNotify.queryString=Expiration Notification User Match
 Setting_Label_pwNotify.intervals=Expiration Notification Intervals