diff --git a/extensions/guacamole-auth-restrict/src/main/java/org/apache/guacamole/auth/restrict/Restrictable.java b/extensions/guacamole-auth-restrict/src/main/java/org/apache/guacamole/auth/restrict/Restrictable.java index ff1acf7450..5feb21477a 100644 --- a/extensions/guacamole-auth-restrict/src/main/java/org/apache/guacamole/auth/restrict/Restrictable.java +++ b/extensions/guacamole-auth-restrict/src/main/java/org/apache/guacamole/auth/restrict/Restrictable.java @@ -27,6 +27,65 @@ */ public interface Restrictable extends Attributes { + /** + * The name of the attribute that contains the absolute date and time after + * which this restrictable object may be used. If this attribute is present + * access to to this object will be denied at any time prior to the parsed + * value of this attribute, regardless of what other restrictions may be + * present to allow access to the object at certain days/times of the week + * or from certain hosts. + */ + public static final String RESTRICT_TIME_AFTER_ATTRIBUTE_NAME = "guac-restrict-time-after"; + + /** + * The name of the attribute that contains a list of weekdays and times (UTC) + * that this restrictable object can be used. The presence of values within + * this attribute will automatically restrict use of the object at any times + * that are not specified. + */ + public static final String RESTRICT_TIME_ALLOWED_ATTRIBUTE_NAME = "guac-restrict-time-allowed"; + + /** + * The name of the attribute that contains the absolute date and time before + * which use of this restrictable object may be used. If this attribute is + * present use of the object will be denied at any time after the parsed + * value of this attribute, regardless of the presence of other restrictions + * that may allow access at certain days/times of the week or from certain + * hosts. + */ + public static final String RESTRICT_TIME_BEFORE_ATTRIBUTE_NAME = "guac-restrict-time-before"; + + /** + * The name of the attribute that contains a list of weekdays and times (UTC) + * that this restrictable object cannot be used. Denied times will always take + * precedence over allowed times. The presence of this attribute without + * guac-restrict-time-allowed will deny access only during the times listed + * in this attribute, allowing access at all other times. The presence of + * this attribute along with the guac-restrict-time-allowed attribute will + * deny access at any times that overlap with the allowed times. + */ + public static final String RESTRICT_TIME_DENIED_ATTRIBUTE_NAME = "guac-restrict-time-denied"; + + /** + * The name of the attribute that contains a list of hosts from which this + * restrictable object may be used. The presence of this attribute will + * restrict use to only users accessing Guacamole from the list of hosts + * contained in the attribute, subject to further restriction by the + * guac-restrict-hosts-denied attribute. + */ + public static final String RESTRICT_HOSTS_ALLOWED_ATTRIBUTE_NAME = "guac-restrict-hosts-allowed"; + + /** + * The name of the attribute that contains a list of hosts from which this + * restrictable object may not be used. The presence of this attribute, + * absent the guac-restrict-hosts-allowed attribute, will allow use from + * all hosts except the ones listed in this attribute. The presence of this + * attribute coupled with the guac-restrict-hosts-allowed attribute will + * block access from any IPs in this list, overriding any that may be + * allowed. + */ + public static final String RESTRICT_HOSTS_DENIED_ATTRIBUTE_NAME = "guac-restrict-hosts-denied"; + /** * Return the restriction state for this restrictable object at the * current date and time. By default returns an implicit denial. diff --git a/extensions/guacamole-auth-restrict/src/main/java/org/apache/guacamole/auth/restrict/RestrictionVerificationService.java b/extensions/guacamole-auth-restrict/src/main/java/org/apache/guacamole/auth/restrict/RestrictionVerificationService.java index 41f0e9f295..ae209360f2 100644 --- a/extensions/guacamole-auth-restrict/src/main/java/org/apache/guacamole/auth/restrict/RestrictionVerificationService.java +++ b/extensions/guacamole-auth-restrict/src/main/java/org/apache/guacamole/auth/restrict/RestrictionVerificationService.java @@ -23,14 +23,14 @@ import inet.ipaddr.HostNameException; import inet.ipaddr.IPAddress; import java.net.UnknownHostException; +import java.text.ParseException; import java.util.Collection; +import java.util.Date; import java.util.List; import java.util.Map; import java.util.Set; import org.apache.guacamole.GuacamoleException; -import org.apache.guacamole.auth.restrict.connection.RestrictedConnection; -import org.apache.guacamole.auth.restrict.user.RestrictedUser; -import org.apache.guacamole.auth.restrict.usergroup.RestrictedUserGroup; +import org.apache.guacamole.auth.restrict.form.DateTimeRestrictionField; import org.apache.guacamole.calendar.DailyRestriction; import org.apache.guacamole.calendar.RestrictionType; import org.apache.guacamole.calendar.TimeRestrictionParser; @@ -54,6 +54,67 @@ public class RestrictionVerificationService { */ private static final Logger LOGGER = LoggerFactory.getLogger(RestrictionVerificationService.class); + /** + * Given the provided strings of an absolute date after which an action is + * valid and before which an action is valid, parse the strings into Date + * objects and determine if the current date and time falls within the + * provided window, returning the appropriate restriction type. + * + * @param afterTimeString + * The string that has the date and time value after which the activity + * is allowed. + * + * @param beforeTimeString + * The string that has the date and time value before which the activity + * is allowed. + * + * @return + * The RestrictionType that represents the allowed or denied state of + * the activity. + */ + private static RestrictionType allowedByDateTimeRestrictions( + String afterTimeString, String beforeTimeString) { + + // Set a default restriction. + RestrictionType dateTimeRestriction = RestrictionType.IMPLICIT_ALLOW; + + // Check the after string and make sure that now is after that date. + if (afterTimeString != null && !afterTimeString.isEmpty()) { + Date now = new Date(); + try { + Date afterTime = DateTimeRestrictionField.parse(afterTimeString); + if (now.before(afterTime)) + return RestrictionType.EXPLICIT_DENY; + } + catch (ParseException e) { + LOGGER.warn("Failed to parse date and time string: {}:", e.getMessage()); + LOGGER.debug("Parse exception while parsing date and time string.", e); + return RestrictionType.IMPLICIT_DENY; + } + dateTimeRestriction = RestrictionType.EXPLICIT_ALLOW; + } + + // Check the before string and make sure that now is prior to that date. + if (beforeTimeString != null && !beforeTimeString.isEmpty()) { + Date now = new Date(); + try { + Date beforeTime = DateTimeRestrictionField.parse(beforeTimeString); + if (now.after(beforeTime)) + return RestrictionType.EXPLICIT_DENY; + } + catch (ParseException e) { + LOGGER.warn("Failed to parse date and time string: {}:", e.getMessage()); + LOGGER.debug("Parse exception while parsing date and time string.", e); + return RestrictionType.IMPLICIT_DENY; + } + dateTimeRestriction = RestrictionType.EXPLICIT_ALLOW; + + } + + // Return the determined RestrictionType for the given date/time strings. + return dateTimeRestriction; + } + /** * Parse out the provided strings of allowed and denied times, verifying * whether or not a login or connection should be allowed at the current @@ -251,8 +312,8 @@ public static void verifyHostRestrictions(UserContext context, Map userAttributes = currentUser.getAttributes(); // Verify host-based restrictions specific to the user - String allowedHostString = userAttributes.get(RestrictedUser.RESTRICT_HOSTS_ALLOWED_ATTRIBUTE_NAME); - String deniedHostString = userAttributes.get(RestrictedUser.RESTRICT_HOSTS_DENIED_ATTRIBUTE_NAME); + String allowedHostString = userAttributes.get(Restrictable.RESTRICT_HOSTS_ALLOWED_ATTRIBUTE_NAME); + String deniedHostString = userAttributes.get(Restrictable.RESTRICT_HOSTS_DENIED_ATTRIBUTE_NAME); RestrictionType hostRestrictionResult = allowedByHostRestrictions(allowedHostString, deniedHostString, remoteAddress); switch (hostRestrictionResult) { @@ -284,8 +345,8 @@ public static void verifyHostRestrictions(UserContext context, Map grpAttributes = userGroup.getAttributes(); // Pull host-based restrictions for this group and verify - String grpAllowedHostString = grpAttributes.get(RestrictedUserGroup.RESTRICT_HOSTS_ALLOWED_ATTRIBUTE_NAME); - String grpDeniedHostString = grpAttributes.get(RestrictedUserGroup.RESTRICT_HOSTS_DENIED_ATTRIBUTE_NAME); + String grpAllowedHostString = grpAttributes.get(Restrictable.RESTRICT_HOSTS_ALLOWED_ATTRIBUTE_NAME); + String grpDeniedHostString = grpAttributes.get(Restrictable.RESTRICT_HOSTS_DENIED_ATTRIBUTE_NAME); RestrictionType grpRestrictionResult = allowedByHostRestrictions(grpAllowedHostString, grpDeniedHostString, remoteAddress); // Any explicit denials are thrown immediately @@ -344,8 +405,8 @@ public static void verifyHostRestrictions(Restrictable restrictable, String remoteAddress) throws GuacamoleException { // Verify time-based restrictions specific to this connection. - String allowedHostsString = restrictable.getAttributes().get(RestrictedConnection.RESTRICT_HOSTS_ALLOWED_ATTRIBUTE_NAME); - String deniedHostsString = restrictable.getAttributes().get(RestrictedConnection.RESTRICT_HOSTS_DENIED_ATTRIBUTE_NAME); + String allowedHostsString = restrictable.getAttributes().get(Restrictable.RESTRICT_HOSTS_ALLOWED_ATTRIBUTE_NAME); + String deniedHostsString = restrictable.getAttributes().get(Restrictable.RESTRICT_HOSTS_DENIED_ATTRIBUTE_NAME); RestrictionType hostRestrictionResult = allowedByHostRestrictions(allowedHostsString, deniedHostsString, remoteAddress); // If the host is not allowed @@ -393,8 +454,8 @@ public static void verifyTimeRestrictions(UserContext context, Map userAttributes = currentUser.getAttributes(); // Verify time-based restrictions specific to the user - String allowedTimeString = userAttributes.get(RestrictedUser.RESTRICT_TIME_ALLOWED_ATTRIBUTE_NAME); - String deniedTimeString = userAttributes.get(RestrictedUser.RESTRICT_TIME_DENIED_ATTRIBUTE_NAME); + String allowedTimeString = userAttributes.get(Restrictable.RESTRICT_TIME_ALLOWED_ATTRIBUTE_NAME); + String deniedTimeString = userAttributes.get(Restrictable.RESTRICT_TIME_DENIED_ATTRIBUTE_NAME); RestrictionType timeRestrictionResult = allowedByTimeRestrictions(allowedTimeString, deniedTimeString); // Check the time restriction for explicit results. @@ -426,8 +487,8 @@ public static void verifyTimeRestrictions(UserContext context, Map grpAttributes = userGroup.getAttributes(); // Pull time-based restrictions for this group and verify - String grpAllowedTimeString = grpAttributes.get(RestrictedUserGroup.RESTRICT_TIME_ALLOWED_ATTRIBUTE_NAME); - String grpDeniedTimeString = grpAttributes.get(RestrictedUserGroup.RESTRICT_TIME_DENIED_ATTRIBUTE_NAME); + String grpAllowedTimeString = grpAttributes.get(Restrictable.RESTRICT_TIME_ALLOWED_ATTRIBUTE_NAME); + String grpDeniedTimeString = grpAttributes.get(Restrictable.RESTRICT_TIME_DENIED_ATTRIBUTE_NAME); RestrictionType grpRestrictionResult = allowedByTimeRestrictions(grpAllowedTimeString, grpDeniedTimeString); // An explicit deny results in immediate denial of the login. @@ -463,6 +524,18 @@ public static void verifyTimeRestrictions(UserContext context, } + public static void verifyDateTimeRestrictions(Restrictable restrictable) throws GuacamoleException { + + String afterTimeString = restrictable.getAttributes().get(Restrictable.RESTRICT_TIME_AFTER_ATTRIBUTE_NAME); + String beforeTimeString = restrictable.getAttributes().get(Restrictable.RESTRICT_TIME_BEFORE_ATTRIBUTE_NAME); + RestrictionType dateRestriction = allowedByDateTimeRestrictions(afterTimeString, beforeTimeString); + if (!dateRestriction.isAllowed()) + throw new TranslatableGuacamoleSecurityException( + "Use of this connection or connection group is not allowed at this time.", + "RESTRICT.ERROR_CONNECTION_NOT_ALLOWED_NOW" + ); + } + /** * Verify the time restrictions for the given Connection object, throwing * an exception if the connection should not be allowed, or silently @@ -478,8 +551,8 @@ public static void verifyTimeRestrictions(UserContext context, public static void verifyTimeRestrictions(Restrictable restrictable) throws GuacamoleException { // Verify time-based restrictions specific to this connection. - String allowedTimeString = restrictable.getAttributes().get(RestrictedConnection.RESTRICT_TIME_ALLOWED_ATTRIBUTE_NAME); - String deniedTimeString = restrictable.getAttributes().get(RestrictedConnection.RESTRICT_TIME_DENIED_ATTRIBUTE_NAME); + String allowedTimeString = restrictable.getAttributes().get(Restrictable.RESTRICT_TIME_ALLOWED_ATTRIBUTE_NAME); + String deniedTimeString = restrictable.getAttributes().get(Restrictable.RESTRICT_TIME_DENIED_ATTRIBUTE_NAME); RestrictionType timeRestriction = allowedByTimeRestrictions(allowedTimeString, deniedTimeString); if (!timeRestriction.isAllowed()) throw new TranslatableGuacamoleSecurityException( @@ -536,6 +609,7 @@ public static void verifyLoginRestrictions(UserContext context, */ public static void verifyConnectionRestrictions(Restrictable restrictable, String remoteAddress) throws GuacamoleException { + verifyDateTimeRestrictions(restrictable); verifyTimeRestrictions(restrictable); verifyHostRestrictions(restrictable, remoteAddress); } diff --git a/extensions/guacamole-auth-restrict/src/main/java/org/apache/guacamole/auth/restrict/connection/RestrictedConnection.java b/extensions/guacamole-auth-restrict/src/main/java/org/apache/guacamole/auth/restrict/connection/RestrictedConnection.java index bdbce0bcc4..08adee54a6 100644 --- a/extensions/guacamole-auth-restrict/src/main/java/org/apache/guacamole/auth/restrict/connection/RestrictedConnection.java +++ b/extensions/guacamole-auth-restrict/src/main/java/org/apache/guacamole/auth/restrict/connection/RestrictedConnection.java @@ -26,6 +26,7 @@ import org.apache.guacamole.GuacamoleException; import org.apache.guacamole.auth.restrict.Restrictable; import org.apache.guacamole.auth.restrict.RestrictionVerificationService; +import org.apache.guacamole.auth.restrict.form.DateTimeRestrictionField; import org.apache.guacamole.auth.restrict.form.HostRestrictionField; import org.apache.guacamole.auth.restrict.form.TimeRestrictionField; import org.apache.guacamole.calendar.RestrictionType; @@ -46,49 +47,12 @@ public class RestrictedConnection extends DelegatingConnection implements Restri */ private final String remoteAddress; - /** - * The name of the attribute that contains a list of weekdays and times (UTC) - * that this connection can be accessed. The presence of values within this - * attribute will automatically restrict use of the connections at any - * times that are not specified. - */ - public static final String RESTRICT_TIME_ALLOWED_ATTRIBUTE_NAME = "guac-restrict-time-allowed"; - - /** - * The name of the attribute that contains a list of weekdays and times (UTC) - * that this connection cannot be accessed. Denied times will always take - * precedence over allowed times. The presence of this attribute without - * guac-restrict-time-allowed will deny access only during the times listed - * in this attribute, allowing access at all other times. The presence of - * this attribute along with the guac-restrict-time-allowed attribute will - * deny access at any times that overlap with the allowed times. - */ - public static final String RESTRICT_TIME_DENIED_ATTRIBUTE_NAME = "guac-restrict-time-denied"; - - /** - * The name of the attribute that contains a list of hosts from which a user - * may access this connection. The presence of this attribute will restrict - * access to only users accessing Guacamole from the list of hosts contained - * in the attribute, subject to further restriction by the - * guac-restrict-hosts-denied attribute. - */ - public static final String RESTRICT_HOSTS_ALLOWED_ATTRIBUTE_NAME = "guac-restrict-hosts-allowed"; - - /** - * The name of the attribute that contains a list of hosts from which - * a user may not access this connection. The presence of this attribute, - * absent the guac-restrict-hosts-allowed attribute, will allow access from - * all hosts except the ones listed in this attribute. The presence of this - * attribute coupled with the guac-restrict-hosts-allowed attribute will - * block access from any IPs in this list, overriding any that may be - * allowed. - */ - public static final String RESTRICT_HOSTS_DENIED_ATTRIBUTE_NAME = "guac-restrict-hosts-denied"; - /** * The list of all connection attributes provided by this Connection implementation. */ public static final List RESTRICT_CONNECTION_ATTRIBUTES = Arrays.asList( + RESTRICT_TIME_AFTER_ATTRIBUTE_NAME, + RESTRICT_TIME_BEFORE_ATTRIBUTE_NAME, RESTRICT_TIME_ALLOWED_ATTRIBUTE_NAME, RESTRICT_TIME_DENIED_ATTRIBUTE_NAME, RESTRICT_HOSTS_ALLOWED_ATTRIBUTE_NAME, @@ -101,6 +65,8 @@ public class RestrictedConnection extends DelegatingConnection implements Restri */ public static final Form RESTRICT_CONNECTION_FORM = new Form("restrict-login-form", Arrays.asList( + new DateTimeRestrictionField(RESTRICT_TIME_AFTER_ATTRIBUTE_NAME), + new DateTimeRestrictionField(RESTRICT_TIME_BEFORE_ATTRIBUTE_NAME), new TimeRestrictionField(RESTRICT_TIME_ALLOWED_ATTRIBUTE_NAME), new TimeRestrictionField(RESTRICT_TIME_DENIED_ATTRIBUTE_NAME), new HostRestrictionField(RESTRICT_HOSTS_ALLOWED_ATTRIBUTE_NAME), diff --git a/extensions/guacamole-auth-restrict/src/main/java/org/apache/guacamole/auth/restrict/connectiongroup/RestrictedConnectionGroup.java b/extensions/guacamole-auth-restrict/src/main/java/org/apache/guacamole/auth/restrict/connectiongroup/RestrictedConnectionGroup.java index b6c18144ef..1f61a26363 100644 --- a/extensions/guacamole-auth-restrict/src/main/java/org/apache/guacamole/auth/restrict/connectiongroup/RestrictedConnectionGroup.java +++ b/extensions/guacamole-auth-restrict/src/main/java/org/apache/guacamole/auth/restrict/connectiongroup/RestrictedConnectionGroup.java @@ -26,6 +26,7 @@ import org.apache.guacamole.GuacamoleException; import org.apache.guacamole.auth.restrict.Restrictable; import org.apache.guacamole.auth.restrict.RestrictionVerificationService; +import org.apache.guacamole.auth.restrict.form.DateTimeRestrictionField; import org.apache.guacamole.auth.restrict.form.HostRestrictionField; import org.apache.guacamole.auth.restrict.form.TimeRestrictionField; import org.apache.guacamole.calendar.RestrictionType; @@ -46,50 +47,13 @@ public class RestrictedConnectionGroup extends DelegatingConnectionGroup impleme */ private final String remoteAddress; - /** - * The name of the attribute that contains a list of weekdays and times (UTC) - * that this connection group can be accessed. The presence of values within - * this attribute will automatically restrict use of the connection group - * at any times that are not specified. - */ - public static final String RESTRICT_TIME_ALLOWED_ATTRIBUTE_NAME = "guac-restrict-time-allowed"; - - /** - * The name of the attribute that contains a list of weekdays and times (UTC) - * that this connection group cannot be accessed. Denied times will always - * take precedence over allowed times. The presence of this attribute without - * guac-restrict-time-allowed will deny access only during the times listed - * in this attribute, allowing access at all other times. The presence of - * this attribute along with the guac-restrict-time-allowed attribute will - * deny access at any times that overlap with the allowed times. - */ - public static final String RESTRICT_TIME_DENIED_ATTRIBUTE_NAME = "guac-restrict-time-denied"; - - /** - * The name of the attribute that contains a list of hosts from which a user - * may access this connection group. The presence of this attribute will - * restrict access to only users accessing Guacamole from the list of hosts - * contained in the attribute, subject to further restriction by the - * guac-restrict-hosts-denied attribute. - */ - public static final String RESTRICT_HOSTS_ALLOWED_ATTRIBUTE_NAME = "guac-restrict-hosts-allowed"; - - /** - * The name of the attribute that contains a list of hosts from which - * a user may not access this connection group. The presence of this - * attribute, absent the guac-restrict-hosts-allowed attribute, will allow - * access from all hosts except the ones listed in this attribute. The - * presence of this attribute coupled with the guac-restrict-hosts-allowed - * attribute will block access from any hosts in this list, overriding any - * that may be allowed. - */ - public static final String RESTRICT_HOSTS_DENIED_ATTRIBUTE_NAME = "guac-restrict-hosts-denied"; - /** * The list of all connection group attributes provided by this * ConnectionGroup implementation. */ public static final List RESTRICT_CONNECTIONGROUP_ATTRIBUTES = Arrays.asList( + RESTRICT_TIME_AFTER_ATTRIBUTE_NAME, + RESTRICT_TIME_BEFORE_ATTRIBUTE_NAME, RESTRICT_TIME_ALLOWED_ATTRIBUTE_NAME, RESTRICT_TIME_DENIED_ATTRIBUTE_NAME, RESTRICT_HOSTS_ALLOWED_ATTRIBUTE_NAME, @@ -102,6 +66,8 @@ public class RestrictedConnectionGroup extends DelegatingConnectionGroup impleme */ public static final Form RESTRICT_CONNECTIONGROUP_FORM = new Form("restrict-login-form", Arrays.asList( + new DateTimeRestrictionField(RESTRICT_TIME_AFTER_ATTRIBUTE_NAME), + new DateTimeRestrictionField(RESTRICT_TIME_BEFORE_ATTRIBUTE_NAME), new TimeRestrictionField(RESTRICT_TIME_ALLOWED_ATTRIBUTE_NAME), new TimeRestrictionField(RESTRICT_TIME_DENIED_ATTRIBUTE_NAME), new HostRestrictionField(RESTRICT_HOSTS_ALLOWED_ATTRIBUTE_NAME), diff --git a/extensions/guacamole-auth-restrict/src/main/java/org/apache/guacamole/auth/restrict/form/DateTimeRestrictionField.java b/extensions/guacamole-auth-restrict/src/main/java/org/apache/guacamole/auth/restrict/form/DateTimeRestrictionField.java new file mode 100644 index 0000000000..91ba5724b2 --- /dev/null +++ b/extensions/guacamole-auth-restrict/src/main/java/org/apache/guacamole/auth/restrict/form/DateTimeRestrictionField.java @@ -0,0 +1,100 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.guacamole.auth.restrict.form; + +import java.text.DateFormat; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Date; +import org.apache.guacamole.form.Field; + +/** + * A field that parses a string containing an absolute date and time value. + */ +public class DateTimeRestrictionField extends Field { + + /** + * The field type. + */ + public static final String FIELD_TYPE = "GUAC_DATETIME_RESTRICTION"; + + /** + * The format of the data for this field as it will be stored in the + * underlying storage mechanism. + */ + public static final String FORMAT = "yyyy-MM-dd'T'HH:mm:ssZ"; + + /** + * Create a new field that tracks time restrictions. + * + * @param name + * The name of the parameter that will be used to pass this field + * between the REST API and the web front-end. + * + */ + public DateTimeRestrictionField(String name) { + super(name, FIELD_TYPE); + } + + /** + * Converts the given date into a string which follows the format used by + * date fields. + * + * @param date + * The date value to format, which may be null. + * + * @return + * The formatted date, or null if the provided time was null. + */ + public static String format(Date date) { + DateFormat dateFormat = new SimpleDateFormat(DateTimeRestrictionField.FORMAT); + return date == null ? null : dateFormat.format(date); + } + + /** + * Parses the given string into a corresponding date. The string must + * follow the standard format used by date fields, as defined by FORMAT + * and as would be produced by format(). + * + * @param dateString + * The date string to parse, which may be null. + * + * @return + * The date corresponding to the given date string, or null if the + * provided date string was null or blank. + * + * @throws ParseException + * If the given date string does not conform to the standard format + * used by date fields. + */ + public static Date parse(String dateString) + throws ParseException { + + // Return null if no date provided + if (dateString == null || dateString.isEmpty()) + return null; + + // Parse date according to format + DateFormat dateFormat = new SimpleDateFormat(DateTimeRestrictionField.FORMAT); + return dateFormat.parse(dateString); + + } + +} diff --git a/extensions/guacamole-auth-restrict/src/main/java/org/apache/guacamole/auth/restrict/usergroup/RestrictedUserGroup.java b/extensions/guacamole-auth-restrict/src/main/java/org/apache/guacamole/auth/restrict/usergroup/RestrictedUserGroup.java index 2e637872b9..6d2d6c51e0 100644 --- a/extensions/guacamole-auth-restrict/src/main/java/org/apache/guacamole/auth/restrict/usergroup/RestrictedUserGroup.java +++ b/extensions/guacamole-auth-restrict/src/main/java/org/apache/guacamole/auth/restrict/usergroup/RestrictedUserGroup.java @@ -23,6 +23,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import org.apache.guacamole.auth.restrict.Restrictable; import org.apache.guacamole.auth.restrict.form.HostRestrictionField; import org.apache.guacamole.auth.restrict.form.TimeRestrictionField; import org.apache.guacamole.form.Form; @@ -33,48 +34,7 @@ * UserGroup implementation which wraps a UserGroup from another extension and * enforces additional restrictions for members of that group. */ -public class RestrictedUserGroup extends DelegatingUserGroup { - - /** - * The name of the attribute that contains a list of weekdays and times (UTC) - * that members of a group are allowed to log in. The presence of this - * attribute will restrict any users who are members of the group to logins - * only during the times that are contained within the attribute, - * subject to further restriction by the guac-restrict-time-denied attribute. - */ - public static final String RESTRICT_TIME_ALLOWED_ATTRIBUTE_NAME = "guac-restrict-time-allowed"; - - /** - * The name of the attribute that contains a list of weekdays and times (UTC) - * that members of a group are not allowed to log in. Denied times will - * always take precedence over allowed times. The presence of this attribute - * without guac-restrict-time-allowed will deny logins only during the times - * listed in this attribute, allowing logins at all other times. The - * presence of this attribute along with the guac-restrict-time-allowed - * attribute will deny logins at any times that overlap with the allowed - * times. - */ - public static final String RESTRICT_TIME_DENIED_ATTRIBUTE_NAME = "guac-restrict-time-denied"; - - /** - * The name of the attribute that contains a list of IP addresses from which - * members of a group are allowed to log in. The presence of this attribute - * will restrict users to only the list of IP addresses contained in the - * attribute, subject to further restriction by the - * guac-restrict-hosts-denied attribute. - */ - public static final String RESTRICT_HOSTS_ALLOWED_ATTRIBUTE_NAME = "guac-restrict-hosts-allowed"; - - /** - * The name of the attribute that contains a list of IP addresses from which - * members of a group are not allowed to log in. The presence of this - * attribute, absent the guac-restrict-hosts-allowed attribute, will allow - * logins from all hosts except the ones listed in this attribute. The - * presence of this attribute coupled with the guac-restrict-hosts-allowed - * attribute will block access from any IPs in this list, overriding any - * that may be allowed. - */ - public static final String RESTRICT_HOSTS_DENIED_ATTRIBUTE_NAME = "guac-restrict-hosts-denied"; +public class RestrictedUserGroup extends DelegatingUserGroup implements Restrictable { /** * The list of all user attributes provided by this UserGroup implementation. diff --git a/extensions/guacamole-auth-restrict/src/main/resources/config/restrictConfig.js b/extensions/guacamole-auth-restrict/src/main/resources/config/restrictConfig.js index 4c63e8a2dd..953b9b9106 100644 --- a/extensions/guacamole-auth-restrict/src/main/resources/config/restrictConfig.js +++ b/extensions/guacamole-auth-restrict/src/main/resources/config/restrictConfig.js @@ -36,5 +36,12 @@ angular.module('guacRestrict').config(['formServiceProvider', controller : 'hostRestrictionFieldController', templateUrl : 'app/ext/restrict/templates/hostRestrictionField.html' }); + + // Define the date and time restriction field + formServiceProvider.registerFieldType('GUAC_DATETIME_RESTRICTION', { + module : 'guacRestrict', + controller : 'dateTimeRestrictionFieldController', + templateUrl : 'app/ext/restrict/templates/dateTimeRestrictionField.html' + }); }]); diff --git a/extensions/guacamole-auth-restrict/src/main/resources/controllers/dateTimeRestrictionFieldController.js b/extensions/guacamole-auth-restrict/src/main/resources/controllers/dateTimeRestrictionFieldController.js new file mode 100644 index 0000000000..6fd2054565 --- /dev/null +++ b/extensions/guacamole-auth-restrict/src/main/resources/controllers/dateTimeRestrictionFieldController.js @@ -0,0 +1,89 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + + +/** + * Controller for date+time restriction fields. + */ +angular.module('form').controller('dateTimeRestrictionFieldController', + ['$scope', '$injector', + function dateTimeRestrictionFieldController($scope, $injector) { + + // Required services + var $filter = $injector.get('$filter'); + + /** + * Options which dictate the behavior of the input field model, as defined + * by https://docs.angularjs.org/api/ng/directive/ngModelOptions + * + * @type Object. + */ + $scope.modelOptions = { + + /** + * Space-delimited list of events on which the model will be updated. + * + * @type String + */ + updateOn : 'blur', + + /** + * The time zone to use when reading/writing the Date object of the + * model. + * + * @type String + */ + timezone : 'UTC' + + }; + + /** + * Parses the date and time components of the given string into a Date in + * the UTC timezone. The input string must be in the format + * YYYY-MM-DDTHH:mm:ss (zero-padded). + * + * @param {String} str + * The date+time string to parse. + * + * @returns {Date} + * A Date object, in the UTC timezone, or null if parsing the provided + * string fails. + */ + var parseDate = function parseDate(str) { + + // Parse date, return null if parsing fails + var parsedDate = new Date(str); + if (isNaN(parsedDate.getTime())) + return null; + + return parsedDate; + + }; + + // Update typed value when model is changed + $scope.$watch('model', function modelChanged(model) { + $scope.typedValue = (model ? parseDate(model) : null); + }); + + // Update string value in model when typed value is changed + $scope.$watch('typedValue', function typedValueChanged(typedValue) { + $scope.model = (typedValue ? $filter('date')(typedValue, 'yyyy-MM-ddTHH:mm:ssZ', 'UTC') : ''); + }); + +}]); diff --git a/extensions/guacamole-auth-restrict/src/main/resources/guac-manifest.json b/extensions/guacamole-auth-restrict/src/main/resources/guac-manifest.json index e0b6928483..7391e23b94 100644 --- a/extensions/guacamole-auth-restrict/src/main/resources/guac-manifest.json +++ b/extensions/guacamole-auth-restrict/src/main/resources/guac-manifest.json @@ -22,8 +22,9 @@ ], "resources" : { - "templates/hostRestrictionField.html" : "text/html", - "templates/timeRestrictionField.html" : "text/html" + "templates/dateTimeRestrictionField.html" : "text/html", + "templates/hostRestrictionField.html" : "text/html", + "templates/timeRestrictionField.html" : "text/html" } } diff --git a/extensions/guacamole-auth-restrict/src/main/resources/templates/dateTimeRestrictionField.html b/extensions/guacamole-auth-restrict/src/main/resources/templates/dateTimeRestrictionField.html new file mode 100644 index 0000000000..8630761fd7 --- /dev/null +++ b/extensions/guacamole-auth-restrict/src/main/resources/templates/dateTimeRestrictionField.html @@ -0,0 +1,12 @@ +
+ +
\ No newline at end of file diff --git a/extensions/guacamole-auth-restrict/src/main/resources/translations/en.json b/extensions/guacamole-auth-restrict/src/main/resources/translations/en.json index 3eb3d04603..2f52d4097b 100644 --- a/extensions/guacamole-auth-restrict/src/main/resources/translations/en.json +++ b/extensions/guacamole-auth-restrict/src/main/resources/translations/en.json @@ -8,7 +8,9 @@ "FIELD_HEADER_GUAC_RESTRICT_HOSTS_ALLOWED" : "Hosts from which connection may be accessed:", "FIELD_HEADER_GUAC_RESTRICT_HOSTS_DENIED" : "Hosts from which connection may not be accessed:", + "FIELD_HEADER_GUAC_RESTRICT_TIME_AFTER" : "Date and time after which this connection may be used:", "FIELD_HEADER_GUAC_RESTRICT_TIME_ALLOWED" : "Times connection is allowed to be used:", + "FIELD_HEADER_GUAC_RESTRICT_TIME_BEFORE" : "Date and time before which this connection may be used:", "FIELD_HEADER_GUAC_RESTRICT_TIME_DENIED" : "Times connection may not be used:", "SECTION_HEADER_RESTRICT_LOGIN_FORM" : "Additional Connection Restrictions" @@ -19,7 +21,9 @@ "FIELD_HEADER_GUAC_RESTRICT_HOSTS_ALLOWED" : "Hosts from which connection group may be accessed:", "FIELD_HEADER_GUAC_RESTRICT_HOSTS_DENIED" : "Hosts from which connection group may not be accessed:", + "FIELD_HEADER_GUAC_RESTRICT_TIME_AFTER" : "Date and time after which this connection group may be used:", "FIELD_HEADER_GUAC_RESTRICT_TIME_ALLOWED" : "Times connection group is allowed to be used:", + "FIELD_HEADER_GUAC_RESTRICT_TIME_BEFORE" : "Date and time before which this connection group may be used:", "FIELD_HEADER_GUAC_RESTRICT_TIME_DENIED" : "Times connection group may not be used:", "SECTION_HEADER_RESTRICT_LOGIN_FORM" : "Additional Connection Restrictions" @@ -35,6 +39,8 @@ "ERROR_USER_LOGIN_NOT_ALLOWED_NOW" : "The login for this user is not allowed at this time.", "ERROR_USER_LOGIN_NOT_ALLOWED_FROM_HOST" : "The login for this user is not allowed from this host.", + "FIELD_PLACEHOLDER_DATE_TIME_RESTRICTION" : "YYYY-MM-DD HH:MM:SS", + "TABLE_HEADER_DAY" : "Day", "TABLE_HEADER_END_TIME" : "End Time", "TABLE_HEADER_HOST" : "Host",