Skip to content

Commit 4a3fc75

Browse files
committed
fix configeditor UI setting testers and add async/timeout functionality
1 parent cc79edd commit 4a3fc75

File tree

7 files changed

+140
-50
lines changed

7 files changed

+140
-50
lines changed

server/src/main/java/password/pwm/error/PwmError.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -306,7 +306,9 @@ public enum PwmError
306306
ERROR_WORDLIST_IMPORT_ERROR(
307307
5094, "Error_WordlistImportError", null ),
308308
ERROR_PWNOTIFY_SERVICE_ERROR(
309-
5095, "Error_PwNotifyServiceError", null ),
309+
5095, "Error_PwNotifyServiceError", Collections.emptySet() ),
310+
ERROR_TIMEOUT(
311+
5096, "Error_Timeout", Collections.emptySet() ),
310312

311313
ERROR_REMOTE_ERROR_VALUE(
312314
6000, "Error_RemoteErrorValue", null, ErrorFlag.Permanent ),

server/src/main/java/password/pwm/error/PwmInternalException.java

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,38 @@
2222

2323
public class PwmInternalException extends RuntimeException
2424
{
25+
protected final ErrorInformation errorInformation;
26+
27+
public PwmInternalException( final ErrorInformation error )
28+
{
29+
this.errorInformation = error == null ? new ErrorInformation( PwmError.ERROR_INTERNAL ) : error;
30+
}
31+
32+
public PwmInternalException( final Throwable cause )
33+
{
34+
super( cause );
35+
this.errorInformation = new ErrorInformation( PwmError.ERROR_INTERNAL, "cause: " + cause.getMessage() );
36+
}
37+
2538
public PwmInternalException( final String message, final Throwable cause )
2639
{
2740
super( message, cause );
41+
this.errorInformation = new ErrorInformation( PwmError.ERROR_INTERNAL, message + ", cause: " + cause.getMessage() );
42+
}
43+
44+
public PwmInternalException( final String message )
45+
{
46+
super( message );
47+
this.errorInformation = new ErrorInformation( PwmError.ERROR_INTERNAL, message );
48+
}
49+
50+
public static PwmInternalException fromPwmException( final String message, final Exception pwmException )
51+
{
52+
return new PwmInternalException( message + ": " + pwmException.getMessage(), pwmException );
53+
}
54+
55+
public static PwmInternalException fromPwmException( final Exception pwmException )
56+
{
57+
return new PwmInternalException( pwmException );
2858
}
2959
}

server/src/main/java/password/pwm/http/servlet/configeditor/ConfigEditorServlet.java

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@
7171
import password.pwm.svc.email.EmailServer;
7272
import password.pwm.svc.email.EmailServerUtil;
7373
import password.pwm.svc.email.EmailService;
74+
import password.pwm.svc.httpclient.PwmHttpClientResponse;
7475
import password.pwm.util.PasswordData;
7576
import password.pwm.util.SampleDataGenerator;
7677
import password.pwm.util.java.JavaHelper;
@@ -606,7 +607,7 @@ private ProcessStatus restSmsHealthCheck(
606607

607608
final Configuration config = new Configuration( configManagerBean.getStoredConfiguration() );
608609
final StringBuilder output = new StringBuilder();
609-
output.append( "beginning SMS send process:\n" );
610+
output.append( "beginning SMS send process.\n" );
610611

611612
if ( !SmsQueueManager.smsIsConfigured( config ) )
612613
{
@@ -618,14 +619,20 @@ private ProcessStatus restSmsHealthCheck(
618619
final SmsItemBean testSmsItem = new SmsItemBean( testParams.get( "to" ), testParams.get( "message" ), pwmRequest.getLabel() );
619620
try
620621
{
621-
final String responseBody = SmsQueueManager.sendDirectMessage(
622+
final PwmHttpClientResponse responseBody = SmsQueueManager.sendDirectMessage(
622623
pwmRequest.getPwmApplication(),
623624
config,
624625
pwmRequest.getLabel(),
625626
testSmsItem
626627
);
627-
output.append( "message sent:\n" );
628-
output.append( "response body: \n" ).append( StringUtil.escapeHtml( responseBody ) );
628+
output.append( "message sent.\n" );
629+
output.append( "response status: " ).append( responseBody.getStatusCode() ).append( "\n" );
630+
if ( responseBody.getHeaders() != null )
631+
{
632+
responseBody.getHeaders().forEach( ( key, value ) ->
633+
output.append( "response header: " ).append( key ).append( ": " ).append( value ).append( "\n" ) );
634+
}
635+
output.append( "response body: \n" ).append( StringUtil.escapeHtml( responseBody.getBody() ) );
629636
}
630637
catch ( final PwmException e )
631638
{
@@ -655,7 +662,7 @@ private ProcessStatus restEmailHealthCheck(
655662
final EmailItemBean testEmailItem = new EmailItemBean( params.get( "to" ), params.get( "from" ), params.get( "subject" ), params.get( "body" ), null );
656663

657664
final StringBuilder output = new StringBuilder();
658-
output.append( "beginning EMail send process:\n" );
665+
output.append( "Beginning EMail send process.\n" );
659666

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

@@ -670,17 +677,17 @@ private ProcessStatus restEmailHealthCheck(
670677
try
671678
{
672679
EmailService.sendEmailSynchronous( emailServer.get(), testConfiguration, testEmailItem, macroRequest );
673-
output.append( "message delivered" );
680+
output.append( "Test message delivered to server.\n" );
674681
}
675682
catch ( final PwmException e )
676683
{
677-
output.append( "error: " + StringUtil.escapeHtml( JavaHelper.readHostileExceptionMessage( e ) ) );
684+
output.append( "error: " ).append( StringUtil.escapeHtml( JavaHelper.readHostileExceptionMessage( e ) ) ).append( "\n" );
678685
}
679686
}
680687
}
681688
else
682689
{
683-
output.append( "smtp service is not configured." );
690+
output.append( "EMail service is not configured.\n" );
684691
}
685692

686693
final RestResultBean restResultBean = RestResultBean.withData( output.toString() );

server/src/main/java/password/pwm/util/PwmScheduler.java

Lines changed: 57 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,10 @@
2323
import org.jetbrains.annotations.NotNull;
2424
import password.pwm.PwmApplication;
2525
import password.pwm.PwmConstants;
26+
import password.pwm.bean.SessionLabel;
27+
import password.pwm.error.PwmError;
28+
import password.pwm.error.PwmInternalException;
29+
import password.pwm.error.PwmUnrecoverableException;
2630
import password.pwm.util.java.AtomicLoopIntIncrementer;
2731
import password.pwm.util.java.JavaHelper;
2832
import password.pwm.util.java.StringUtil;
@@ -34,6 +38,8 @@
3438
import java.util.GregorianCalendar;
3539
import java.util.Objects;
3640
import java.util.TimeZone;
41+
import java.util.concurrent.Callable;
42+
import java.util.concurrent.ExecutionException;
3743
import java.util.concurrent.ExecutorService;
3844
import java.util.concurrent.Executors;
3945
import java.util.concurrent.Future;
@@ -42,6 +48,7 @@
4248
import java.util.concurrent.ThreadFactory;
4349
import java.util.concurrent.ThreadPoolExecutor;
4450
import java.util.concurrent.TimeUnit;
51+
import java.util.concurrent.TimeoutException;
4552

4653
public class PwmScheduler
4754
{
@@ -320,6 +327,55 @@ public static Instant nextZuluZeroTime( )
320327
nextZuluMidnight.set( Calendar.MINUTE, 0 );
321328
nextZuluMidnight.set( Calendar.SECOND, 0 );
322329
nextZuluMidnight.add( Calendar.HOUR, 24 );
323-
return nextZuluMidnight.getTime().toInstant();
330+
return nextZuluMidnight.toInstant();
331+
}
332+
333+
/**
334+
* Execute a task within the time period specified by {@code maxWaitDuration}. If the task exceeds the time allotted, it is
335+
* cancelled and the results are discarded. The calling thread will block until the callable returns
336+
* a result or the {@code maxWaitDuration} is reached, whichever occurs first.
337+
* @param pwmApplication application to use for thread naming and other housekeeping.
338+
*
339+
* @param label thread labels.
340+
* @param maxWaitDuration maximum time to wait for result.
341+
* @param callable task to execute.
342+
* @param <T> return value of the callable.
343+
* @return The {@code callable}'s return value.
344+
* @throws PwmUnrecoverableException if the task times out. Uses {@link PwmError#ERROR_TIMEOUT}.
345+
* @throws Throwable any throwable generated by the {@code callable}
346+
*/
347+
public static <T> T timeoutExecutor(
348+
final PwmApplication pwmApplication,
349+
final SessionLabel label,
350+
final TimeDuration maxWaitDuration,
351+
final Callable<T> callable
352+
)
353+
throws PwmUnrecoverableException, Throwable
354+
{
355+
356+
final ScheduledExecutorService executor = PwmScheduler.makeSingleThreadExecutorService( pwmApplication, callable.getClass() );
357+
358+
try
359+
{
360+
final Future<T> future = executor.submit( callable );
361+
362+
return future.get( maxWaitDuration.asMillis(), TimeUnit.MILLISECONDS );
363+
}
364+
catch ( final ExecutionException e )
365+
{
366+
throw e.getCause();
367+
}
368+
catch ( final TimeoutException e )
369+
{
370+
throw PwmUnrecoverableException.newException( PwmError.ERROR_TIMEOUT, "operation timed out: " + e.getMessage() );
371+
}
372+
catch ( final Exception e )
373+
{
374+
throw PwmInternalException.fromPwmException( e );
375+
}
376+
finally
377+
{
378+
executor.shutdownNow();
379+
}
324380
}
325381
}

server/src/main/java/password/pwm/util/queue/SmsQueueManager.java

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -479,7 +479,7 @@ private static class SmsSendEngine
479479
private static final PwmLogger LOGGER = PwmLogger.forClass( SmsSendEngine.class );
480480
private final PwmApplication pwmApplication;
481481
private final Configuration config;
482-
private String lastResponseBody;
482+
private PwmHttpClientResponse lastResponse;
483483

484484
private SmsSendEngine( final PwmApplication pwmApplication, final Configuration configuration )
485485
{
@@ -490,7 +490,7 @@ private SmsSendEngine( final PwmApplication pwmApplication, final Configuration
490490
protected void sendSms( final String to, final String message, final SessionLabel sessionLabel )
491491
throws PwmUnrecoverableException, PwmOperationalException
492492
{
493-
lastResponseBody = null;
493+
lastResponse = null;
494494

495495
final String requestData = makeRequestData( to, message );
496496

@@ -519,9 +519,9 @@ protected void sendSms( final String to, final String message, final SessionLabe
519519
{
520520
final PwmHttpClientResponse pwmHttpClientResponse = pwmHttpClient.makeRequest( pwmHttpClientRequest, sessionLabel );
521521
final int resultCode = pwmHttpClientResponse.getStatusCode();
522+
lastResponse = pwmHttpClientResponse;
522523

523524
final String responseBody = pwmHttpClientResponse.getBody();
524-
lastResponseBody = responseBody;
525525

526526
determineIfResultSuccessful( config, resultCode, responseBody );
527527
LOGGER.debug( () -> "SMS send successful, HTTP status: " + resultCode );
@@ -660,13 +660,13 @@ private PwmHttpClientRequest makeRequest(
660660
.build();
661661
}
662662

663-
public String getLastResponseBody( )
663+
public PwmHttpClientResponse getLastResponse( )
664664
{
665-
return lastResponseBody;
665+
return lastResponse;
666666
}
667667
}
668668

669-
public static String sendDirectMessage(
669+
public static PwmHttpClientResponse sendDirectMessage(
670670
final PwmApplication pwmApplication,
671671
final Configuration configuration,
672672
final SessionLabel sessionLabel,
@@ -677,7 +677,7 @@ public static String sendDirectMessage(
677677
{
678678
final SmsSendEngine smsSendEngine = new SmsSendEngine( pwmApplication, configuration );
679679
smsSendEngine.sendSms( smsItemBean.getTo(), smsItemBean.getMessage(), sessionLabel );
680-
return smsSendEngine.getLastResponseBody();
680+
return smsSendEngine.getLastResponse();
681681
}
682682

683683
public int queueSize( )

server/src/main/resources/password/pwm/i18n/Error.properties

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,7 @@ Error_NodeServiceError=An error occurred with the node service: %1%. Check the
165165
Error_RemoteErrorValue=Remote Error: %1%
166166
Error_WordlistImportError=An error occurred importing the wordlist: %1%
167167
Error_PwNotifyServiceError=An error occurred while running the password notify service: %1%
168+
Error_Timeout=The requested operation has timed out
168169

169170
Error_ConfigUploadSuccess=File uploaded successfully
170171
Error_ConfigUploadFailure=File failed to upload.

webapp/src/main/webapp/public/resources/js/configeditor.js

Lines changed: 27 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -829,50 +829,44 @@ PWM_CFGEDIT.httpsCertificateView = function() {
829829
};
830830

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

850-
};
851-
PWM_MAIN.ajaxRequest(url,loadFunction,{content:formData});
852-
}});
853-
}});
834+
var dialogFormRows = '<p>' + PWM_CONFIG.showString('Warning_SmsTestData') +'</p>'
835+
+ '<tr><td>To</td><td><input name="to" type="text" value="555-1212"/></td></tr>'
836+
+ '<tr><td>Message</td><td><input name="message" type="text" value="Test Message"/></td></tr>';
837+
838+
var actionParam = 'smsHealthCheck';
839+
840+
PWM_CFGEDIT.healthCheckImpl(dialogFormRows,title,actionParam);
854841
};
855842

856843
PWM_CFGEDIT.emailHealthCheck = function() {
857-
var dialogBody = '<p>' + PWM_CONFIG.showString('Warning_EmailTestData') + '</p><form id="emailCheckParametersForm"><table>';
858-
dialogBody += '<tr><td>To</td><td><input name="to" type="text" value="[email protected]"/></td></tr>';
859-
dialogBody += '<tr><td>From</td><td><input name="from" type="text" value="@DefaultEmailFromAddress@"/></td></tr>';
860-
dialogBody += '<tr><td>Subject</td><td><input name="subject" type="text" value="Test Email"/></td></tr>';
861-
dialogBody += '<tr><td>Body</td><td><input name="body" type="text" value="Test Email""/></td></tr>';
862-
dialogBody += '</table></form>';
863-
PWM_MAIN.showDialog({text:dialogBody,showCancel:true,title:'Test Email Connection',closeOnOk:false,okAction:function(){
864-
var formElement = PWM_MAIN.getObject("emailCheckParametersForm");
844+
var title = PWM_CONFIG.showString('Warning_EmailTestData');
845+
846+
var dialogFormRows = '<tr><td>To</td><td><input name="to" type="text" value="[email protected]"/></td></tr>'
847+
+ '<tr><td>From</td><td><input name="from" type="text" value="@DefaultEmailFromAddress@"/></td></tr>'
848+
+ '<tr><td>Subject</td><td><input name="subject" type="text" value="Test Email"/></td></tr>'
849+
+ '<tr><td>Body</td><td><input name="body" type="text" value="Test Email""/></td></tr>';
850+
851+
var actionParam = 'emailHealthCheck';
852+
853+
PWM_CFGEDIT.healthCheckImpl(dialogFormRows,title,actionParam);
854+
};
855+
856+
PWM_CFGEDIT.healthCheckImpl = function(dialogFormRows, title, actionParam) {
857+
var formBody = '<form id="parametersForm"><table>' + dialogFormRows + '</table></form>';
858+
PWM_MAIN.showDialog({text:formBody,showCancel:true,title:title,closeOnOk:false,okAction:function(){
859+
var formElement = PWM_MAIN.getObject("parametersForm");
865860
var formData = PWM_MAIN.JSLibrary.formToValueMap(formElement);
866-
var url = "editor?processAction=emailHealthCheck";
861+
var url = PWM_MAIN.addParamToUrl(window.location.pathname, 'processAction', actionParam);
867862
url = PWM_MAIN.addParamToUrl(url,'profile',PWM_CFGEDIT.readCurrentProfile());
868863
PWM_MAIN.showWaitDialog({loadFunction:function(){
869864
var loadFunction = function(data) {
870865
if (data['error']) {
871866
PWM_MAIN.showErrorDialog(data);
872867
} else {
873-
var bodyText = PWM_ADMIN.makeHealthHtml(data['data'],false,false);
874-
var titleText = 'Email Send Message Status';
875-
PWM_MAIN.showDialog({text:bodyText,title:titleText,showCancel:true});
868+
var bodyText = '<div class="logViewer">' + data['data'] + '</div>';
869+
PWM_MAIN.showDialog({text:bodyText,title:title,showCancel:true,dialogClass:'wide'});
876870
}
877871
};
878872
PWM_MAIN.ajaxRequest(url,loadFunction,{content:formData});

0 commit comments

Comments
 (0)