Skip to content

Commit

Permalink
fix configeditor UI setting testers and add async/timeout functionality
Browse files Browse the repository at this point in the history
  • Loading branch information
jrivard committed Sep 24, 2022
1 parent cc79edd commit 4a3fc75
Show file tree
Hide file tree
Showing 7 changed files with 140 additions and 50 deletions.
4 changes: 3 additions & 1 deletion server/src/main/java/password/pwm/error/PwmError.java
Original file line number Diff line number Diff line change
Expand Up @@ -306,7 +306,9 @@ public enum PwmError
ERROR_WORDLIST_IMPORT_ERROR(
5094, "Error_WordlistImportError", null ),
ERROR_PWNOTIFY_SERVICE_ERROR(
5095, "Error_PwNotifyServiceError", null ),
5095, "Error_PwNotifyServiceError", Collections.emptySet() ),
ERROR_TIMEOUT(
5096, "Error_Timeout", Collections.emptySet() ),

ERROR_REMOTE_ERROR_VALUE(
6000, "Error_RemoteErrorValue", null, ErrorFlag.Permanent ),
Expand Down
30 changes: 30 additions & 0 deletions server/src/main/java/password/pwm/error/PwmInternalException.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,38 @@

public class PwmInternalException extends RuntimeException
{
protected final ErrorInformation errorInformation;

public PwmInternalException( final ErrorInformation error )
{
this.errorInformation = error == null ? new ErrorInformation( PwmError.ERROR_INTERNAL ) : error;
}

public PwmInternalException( final Throwable cause )
{
super( cause );
this.errorInformation = new ErrorInformation( PwmError.ERROR_INTERNAL, "cause: " + cause.getMessage() );
}

public PwmInternalException( final String message, final Throwable cause )
{
super( message, cause );
this.errorInformation = new ErrorInformation( PwmError.ERROR_INTERNAL, message + ", cause: " + cause.getMessage() );
}

public PwmInternalException( final String message )
{
super( message );
this.errorInformation = new ErrorInformation( PwmError.ERROR_INTERNAL, message );
}

public static PwmInternalException fromPwmException( final String message, final Exception pwmException )
{
return new PwmInternalException( message + ": " + pwmException.getMessage(), pwmException );
}

public static PwmInternalException fromPwmException( final Exception pwmException )
{
return new PwmInternalException( pwmException );
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@
import password.pwm.svc.email.EmailServer;
import password.pwm.svc.email.EmailServerUtil;
import password.pwm.svc.email.EmailService;
import password.pwm.svc.httpclient.PwmHttpClientResponse;
import password.pwm.util.PasswordData;
import password.pwm.util.SampleDataGenerator;
import password.pwm.util.java.JavaHelper;
Expand Down Expand Up @@ -606,7 +607,7 @@ private ProcessStatus restSmsHealthCheck(

final Configuration config = new Configuration( configManagerBean.getStoredConfiguration() );
final StringBuilder output = new StringBuilder();
output.append( "beginning SMS send process:\n" );
output.append( "beginning SMS send process.\n" );

if ( !SmsQueueManager.smsIsConfigured( config ) )
{
Expand All @@ -618,14 +619,20 @@ private ProcessStatus restSmsHealthCheck(
final SmsItemBean testSmsItem = new SmsItemBean( testParams.get( "to" ), testParams.get( "message" ), pwmRequest.getLabel() );
try
{
final String responseBody = SmsQueueManager.sendDirectMessage(
final PwmHttpClientResponse responseBody = SmsQueueManager.sendDirectMessage(
pwmRequest.getPwmApplication(),
config,
pwmRequest.getLabel(),
testSmsItem
);
output.append( "message sent:\n" );
output.append( "response body: \n" ).append( StringUtil.escapeHtml( responseBody ) );
output.append( "message sent.\n" );
output.append( "response status: " ).append( responseBody.getStatusCode() ).append( "\n" );
if ( responseBody.getHeaders() != null )
{
responseBody.getHeaders().forEach( ( key, value ) ->
output.append( "response header: " ).append( key ).append( ": " ).append( value ).append( "\n" ) );
}
output.append( "response body: \n" ).append( StringUtil.escapeHtml( responseBody.getBody() ) );
}
catch ( final PwmException e )
{
Expand Down Expand Up @@ -655,7 +662,7 @@ private ProcessStatus restEmailHealthCheck(
final EmailItemBean testEmailItem = new EmailItemBean( params.get( "to" ), params.get( "from" ), params.get( "subject" ), params.get( "body" ), null );

final StringBuilder output = new StringBuilder();
output.append( "beginning EMail send process:\n" );
output.append( "Beginning EMail send process.\n" );

final Configuration testConfiguration = new Configuration( configManagerBean.getStoredConfiguration() );

Expand All @@ -670,17 +677,17 @@ private ProcessStatus restEmailHealthCheck(
try
{
EmailService.sendEmailSynchronous( emailServer.get(), testConfiguration, testEmailItem, macroRequest );
output.append( "message delivered" );
output.append( "Test message delivered to server.\n" );
}
catch ( final PwmException e )
{
output.append( "error: " + StringUtil.escapeHtml( JavaHelper.readHostileExceptionMessage( e ) ) );
output.append( "error: " ).append( StringUtil.escapeHtml( JavaHelper.readHostileExceptionMessage( e ) ) ).append( "\n" );
}
}
}
else
{
output.append( "smtp service is not configured." );
output.append( "EMail service is not configured.\n" );
}

final RestResultBean restResultBean = RestResultBean.withData( output.toString() );
Expand Down
58 changes: 57 additions & 1 deletion server/src/main/java/password/pwm/util/PwmScheduler.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@
import org.jetbrains.annotations.NotNull;
import password.pwm.PwmApplication;
import password.pwm.PwmConstants;
import password.pwm.bean.SessionLabel;
import password.pwm.error.PwmError;
import password.pwm.error.PwmInternalException;
import password.pwm.error.PwmUnrecoverableException;
import password.pwm.util.java.AtomicLoopIntIncrementer;
import password.pwm.util.java.JavaHelper;
import password.pwm.util.java.StringUtil;
Expand All @@ -34,6 +38,8 @@
import java.util.GregorianCalendar;
import java.util.Objects;
import java.util.TimeZone;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
Expand All @@ -42,6 +48,7 @@
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

public class PwmScheduler
{
Expand Down Expand Up @@ -320,6 +327,55 @@ public static Instant nextZuluZeroTime( )
nextZuluMidnight.set( Calendar.MINUTE, 0 );
nextZuluMidnight.set( Calendar.SECOND, 0 );
nextZuluMidnight.add( Calendar.HOUR, 24 );
return nextZuluMidnight.getTime().toInstant();
return nextZuluMidnight.toInstant();
}

/**
* Execute a task within the time period specified by {@code maxWaitDuration}. If the task exceeds the time allotted, it is
* cancelled and the results are discarded. The calling thread will block until the callable returns
* a result or the {@code maxWaitDuration} is reached, whichever occurs first.
* @param pwmApplication application to use for thread naming and other housekeeping.
*
* @param label thread labels.
* @param maxWaitDuration maximum time to wait for result.
* @param callable task to execute.
* @param <T> return value of the callable.
* @return The {@code callable}'s return value.
* @throws PwmUnrecoverableException if the task times out. Uses {@link PwmError#ERROR_TIMEOUT}.
* @throws Throwable any throwable generated by the {@code callable}
*/
public static <T> T timeoutExecutor(
final PwmApplication pwmApplication,
final SessionLabel label,
final TimeDuration maxWaitDuration,
final Callable<T> callable
)
throws PwmUnrecoverableException, Throwable
{

final ScheduledExecutorService executor = PwmScheduler.makeSingleThreadExecutorService( pwmApplication, callable.getClass() );

try
{
final Future<T> future = executor.submit( callable );

return future.get( maxWaitDuration.asMillis(), TimeUnit.MILLISECONDS );
}
catch ( final ExecutionException e )
{
throw e.getCause();
}
catch ( final TimeoutException e )
{
throw PwmUnrecoverableException.newException( PwmError.ERROR_TIMEOUT, "operation timed out: " + e.getMessage() );
}
catch ( final Exception e )
{
throw PwmInternalException.fromPwmException( e );
}
finally
{
executor.shutdownNow();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -479,7 +479,7 @@ private static class SmsSendEngine
private static final PwmLogger LOGGER = PwmLogger.forClass( SmsSendEngine.class );
private final PwmApplication pwmApplication;
private final Configuration config;
private String lastResponseBody;
private PwmHttpClientResponse lastResponse;

private SmsSendEngine( final PwmApplication pwmApplication, final Configuration configuration )
{
Expand All @@ -490,7 +490,7 @@ private SmsSendEngine( final PwmApplication pwmApplication, final Configuration
protected void sendSms( final String to, final String message, final SessionLabel sessionLabel )
throws PwmUnrecoverableException, PwmOperationalException
{
lastResponseBody = null;
lastResponse = null;

final String requestData = makeRequestData( to, message );

Expand Down Expand Up @@ -519,9 +519,9 @@ protected void sendSms( final String to, final String message, final SessionLabe
{
final PwmHttpClientResponse pwmHttpClientResponse = pwmHttpClient.makeRequest( pwmHttpClientRequest, sessionLabel );
final int resultCode = pwmHttpClientResponse.getStatusCode();
lastResponse = pwmHttpClientResponse;

final String responseBody = pwmHttpClientResponse.getBody();
lastResponseBody = responseBody;

determineIfResultSuccessful( config, resultCode, responseBody );
LOGGER.debug( () -> "SMS send successful, HTTP status: " + resultCode );
Expand Down Expand Up @@ -660,13 +660,13 @@ private PwmHttpClientRequest makeRequest(
.build();
}

public String getLastResponseBody( )
public PwmHttpClientResponse getLastResponse( )
{
return lastResponseBody;
return lastResponse;
}
}

public static String sendDirectMessage(
public static PwmHttpClientResponse sendDirectMessage(
final PwmApplication pwmApplication,
final Configuration configuration,
final SessionLabel sessionLabel,
Expand All @@ -677,7 +677,7 @@ public static String sendDirectMessage(
{
final SmsSendEngine smsSendEngine = new SmsSendEngine( pwmApplication, configuration );
smsSendEngine.sendSms( smsItemBean.getTo(), smsItemBean.getMessage(), sessionLabel );
return smsSendEngine.getLastResponseBody();
return smsSendEngine.getLastResponse();
}

public int queueSize( )
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,7 @@ Error_NodeServiceError=An error occurred with the node service: %1%. Check the
Error_RemoteErrorValue=Remote Error: %1%
Error_WordlistImportError=An error occurred importing the wordlist: %1%
Error_PwNotifyServiceError=An error occurred while running the password notify service: %1%
Error_Timeout=The requested operation has timed out

Error_ConfigUploadSuccess=File uploaded successfully
Error_ConfigUploadFailure=File failed to upload.
Expand Down
60 changes: 27 additions & 33 deletions webapp/src/main/webapp/public/resources/js/configeditor.js
Original file line number Diff line number Diff line change
Expand Up @@ -829,50 +829,44 @@ PWM_CFGEDIT.httpsCertificateView = function() {
};

PWM_CFGEDIT.smsHealthCheck = function() {
var dialogBody = '<p>' + PWM_CONFIG.showString('Warning_SmsTestData') + '</p><form id="smsCheckParametersForm"><table>';
dialogBody += '<tr><td>To</td><td><input name="to" type="text" value="555-1212"/></td></tr>';
dialogBody += '<tr><td>Message</td><td><input name="message" type="text" value="Test Message"/></td></tr>';
dialogBody += '</table></form>';
PWM_MAIN.showDialog({text:dialogBody,showCancel:true,title:'Test SMS connection',closeOnOk:false,okAction:function(){
var formElement = PWM_MAIN.getObject("smsCheckParametersForm");
var formData = PWM_MAIN.JSLibrary.formToValueMap(formElement);
var url = "editor?processAction=smsHealthCheck";
PWM_MAIN.showWaitDialog({loadFunction:function(){
var loadFunction = function(data) {
if (data['error']) {
PWM_MAIN.showErrorDialog(data);
} else {
var bodyText = PWM_ADMIN.makeHealthHtml(data['data'],false,false);
var titleText = 'SMS Send Message Status';
PWM_MAIN.showDialog({text:bodyText,title:titleText,showCancel:true});
}
var title = 'Test SMS Settings'

};
PWM_MAIN.ajaxRequest(url,loadFunction,{content:formData});
}});
}});
var dialogFormRows = '<p>' + PWM_CONFIG.showString('Warning_SmsTestData') +'</p>'
+ '<tr><td>To</td><td><input name="to" type="text" value="555-1212"/></td></tr>'
+ '<tr><td>Message</td><td><input name="message" type="text" value="Test Message"/></td></tr>';

var actionParam = 'smsHealthCheck';

PWM_CFGEDIT.healthCheckImpl(dialogFormRows,title,actionParam);
};

PWM_CFGEDIT.emailHealthCheck = function() {
var dialogBody = '<p>' + PWM_CONFIG.showString('Warning_EmailTestData') + '</p><form id="emailCheckParametersForm"><table>';
dialogBody += '<tr><td>To</td><td><input name="to" type="text" value="[email protected]"/></td></tr>';
dialogBody += '<tr><td>From</td><td><input name="from" type="text" value="@DefaultEmailFromAddress@"/></td></tr>';
dialogBody += '<tr><td>Subject</td><td><input name="subject" type="text" value="Test Email"/></td></tr>';
dialogBody += '<tr><td>Body</td><td><input name="body" type="text" value="Test Email""/></td></tr>';
dialogBody += '</table></form>';
PWM_MAIN.showDialog({text:dialogBody,showCancel:true,title:'Test Email Connection',closeOnOk:false,okAction:function(){
var formElement = PWM_MAIN.getObject("emailCheckParametersForm");
var title = PWM_CONFIG.showString('Warning_EmailTestData');

var dialogFormRows = '<tr><td>To</td><td><input name="to" type="text" value="[email protected]"/></td></tr>'
+ '<tr><td>From</td><td><input name="from" type="text" value="@DefaultEmailFromAddress@"/></td></tr>'
+ '<tr><td>Subject</td><td><input name="subject" type="text" value="Test Email"/></td></tr>'
+ '<tr><td>Body</td><td><input name="body" type="text" value="Test Email""/></td></tr>';

var actionParam = 'emailHealthCheck';

PWM_CFGEDIT.healthCheckImpl(dialogFormRows,title,actionParam);
};

PWM_CFGEDIT.healthCheckImpl = function(dialogFormRows, title, actionParam) {
var formBody = '<form id="parametersForm"><table>' + dialogFormRows + '</table></form>';
PWM_MAIN.showDialog({text:formBody,showCancel:true,title:title,closeOnOk:false,okAction:function(){
var formElement = PWM_MAIN.getObject("parametersForm");
var formData = PWM_MAIN.JSLibrary.formToValueMap(formElement);
var url = "editor?processAction=emailHealthCheck";
var url = PWM_MAIN.addParamToUrl(window.location.pathname, 'processAction', actionParam);
url = PWM_MAIN.addParamToUrl(url,'profile',PWM_CFGEDIT.readCurrentProfile());
PWM_MAIN.showWaitDialog({loadFunction:function(){
var loadFunction = function(data) {
if (data['error']) {
PWM_MAIN.showErrorDialog(data);
} else {
var bodyText = PWM_ADMIN.makeHealthHtml(data['data'],false,false);
var titleText = 'Email Send Message Status';
PWM_MAIN.showDialog({text:bodyText,title:titleText,showCancel:true});
var bodyText = '<div class="logViewer">' + data['data'] + '</div>';
PWM_MAIN.showDialog({text:bodyText,title:title,showCancel:true,dialogClass:'wide'});
}
};
PWM_MAIN.ajaxRequest(url,loadFunction,{content:formData});
Expand Down

0 comments on commit 4a3fc75

Please sign in to comment.