GUACAMOLE-1701: Implement connection date and time before and after restrictions.

This commit is contained in:
Virtually Nick
2024-10-04 06:16:53 -04:00
parent bbede31adc
commit 32eaffce62
11 changed files with 377 additions and 137 deletions

View File

@@ -27,6 +27,65 @@ import org.apache.guacamole.net.auth.Attributes;
*/ */
public interface Restrictable extends Attributes { 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 * Return the restriction state for this restrictable object at the
* current date and time. By default returns an implicit denial. * current date and time. By default returns an implicit denial.

View File

@@ -23,14 +23,14 @@ import inet.ipaddr.HostName;
import inet.ipaddr.HostNameException; import inet.ipaddr.HostNameException;
import inet.ipaddr.IPAddress; import inet.ipaddr.IPAddress;
import java.net.UnknownHostException; import java.net.UnknownHostException;
import java.text.ParseException;
import java.util.Collection; import java.util.Collection;
import java.util.Date;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import org.apache.guacamole.GuacamoleException; import org.apache.guacamole.GuacamoleException;
import org.apache.guacamole.auth.restrict.connection.RestrictedConnection; import org.apache.guacamole.auth.restrict.form.DateTimeRestrictionField;
import org.apache.guacamole.auth.restrict.user.RestrictedUser;
import org.apache.guacamole.auth.restrict.usergroup.RestrictedUserGroup;
import org.apache.guacamole.calendar.DailyRestriction; import org.apache.guacamole.calendar.DailyRestriction;
import org.apache.guacamole.calendar.RestrictionType; import org.apache.guacamole.calendar.RestrictionType;
import org.apache.guacamole.calendar.TimeRestrictionParser; import org.apache.guacamole.calendar.TimeRestrictionParser;
@@ -54,6 +54,67 @@ public class RestrictionVerificationService {
*/ */
private static final Logger LOGGER = LoggerFactory.getLogger(RestrictionVerificationService.class); 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 * Parse out the provided strings of allowed and denied times, verifying
* whether or not a login or connection should be allowed at the current * whether or not a login or connection should be allowed at the current
@@ -251,8 +312,8 @@ public class RestrictionVerificationService {
Map<String, String> userAttributes = currentUser.getAttributes(); Map<String, String> userAttributes = currentUser.getAttributes();
// Verify host-based restrictions specific to the user // Verify host-based restrictions specific to the user
String allowedHostString = userAttributes.get(RestrictedUser.RESTRICT_HOSTS_ALLOWED_ATTRIBUTE_NAME); String allowedHostString = userAttributes.get(Restrictable.RESTRICT_HOSTS_ALLOWED_ATTRIBUTE_NAME);
String deniedHostString = userAttributes.get(RestrictedUser.RESTRICT_HOSTS_DENIED_ATTRIBUTE_NAME); String deniedHostString = userAttributes.get(Restrictable.RESTRICT_HOSTS_DENIED_ATTRIBUTE_NAME);
RestrictionType hostRestrictionResult = allowedByHostRestrictions(allowedHostString, deniedHostString, remoteAddress); RestrictionType hostRestrictionResult = allowedByHostRestrictions(allowedHostString, deniedHostString, remoteAddress);
switch (hostRestrictionResult) { switch (hostRestrictionResult) {
@@ -284,8 +345,8 @@ public class RestrictionVerificationService {
Map<String, String> grpAttributes = userGroup.getAttributes(); Map<String, String> grpAttributes = userGroup.getAttributes();
// Pull host-based restrictions for this group and verify // Pull host-based restrictions for this group and verify
String grpAllowedHostString = grpAttributes.get(RestrictedUserGroup.RESTRICT_HOSTS_ALLOWED_ATTRIBUTE_NAME); String grpAllowedHostString = grpAttributes.get(Restrictable.RESTRICT_HOSTS_ALLOWED_ATTRIBUTE_NAME);
String grpDeniedHostString = grpAttributes.get(RestrictedUserGroup.RESTRICT_HOSTS_DENIED_ATTRIBUTE_NAME); String grpDeniedHostString = grpAttributes.get(Restrictable.RESTRICT_HOSTS_DENIED_ATTRIBUTE_NAME);
RestrictionType grpRestrictionResult = allowedByHostRestrictions(grpAllowedHostString, grpDeniedHostString, remoteAddress); RestrictionType grpRestrictionResult = allowedByHostRestrictions(grpAllowedHostString, grpDeniedHostString, remoteAddress);
// Any explicit denials are thrown immediately // Any explicit denials are thrown immediately
@@ -344,8 +405,8 @@ public class RestrictionVerificationService {
String remoteAddress) throws GuacamoleException { String remoteAddress) throws GuacamoleException {
// Verify time-based restrictions specific to this connection. // Verify time-based restrictions specific to this connection.
String allowedHostsString = restrictable.getAttributes().get(RestrictedConnection.RESTRICT_HOSTS_ALLOWED_ATTRIBUTE_NAME); String allowedHostsString = restrictable.getAttributes().get(Restrictable.RESTRICT_HOSTS_ALLOWED_ATTRIBUTE_NAME);
String deniedHostsString = restrictable.getAttributes().get(RestrictedConnection.RESTRICT_HOSTS_DENIED_ATTRIBUTE_NAME); String deniedHostsString = restrictable.getAttributes().get(Restrictable.RESTRICT_HOSTS_DENIED_ATTRIBUTE_NAME);
RestrictionType hostRestrictionResult = allowedByHostRestrictions(allowedHostsString, deniedHostsString, remoteAddress); RestrictionType hostRestrictionResult = allowedByHostRestrictions(allowedHostsString, deniedHostsString, remoteAddress);
// If the host is not allowed // If the host is not allowed
@@ -393,8 +454,8 @@ public class RestrictionVerificationService {
Map<String, String> userAttributes = currentUser.getAttributes(); Map<String, String> userAttributes = currentUser.getAttributes();
// Verify time-based restrictions specific to the user // Verify time-based restrictions specific to the user
String allowedTimeString = userAttributes.get(RestrictedUser.RESTRICT_TIME_ALLOWED_ATTRIBUTE_NAME); String allowedTimeString = userAttributes.get(Restrictable.RESTRICT_TIME_ALLOWED_ATTRIBUTE_NAME);
String deniedTimeString = userAttributes.get(RestrictedUser.RESTRICT_TIME_DENIED_ATTRIBUTE_NAME); String deniedTimeString = userAttributes.get(Restrictable.RESTRICT_TIME_DENIED_ATTRIBUTE_NAME);
RestrictionType timeRestrictionResult = allowedByTimeRestrictions(allowedTimeString, deniedTimeString); RestrictionType timeRestrictionResult = allowedByTimeRestrictions(allowedTimeString, deniedTimeString);
// Check the time restriction for explicit results. // Check the time restriction for explicit results.
@@ -426,8 +487,8 @@ public class RestrictionVerificationService {
Map<String, String> grpAttributes = userGroup.getAttributes(); Map<String, String> grpAttributes = userGroup.getAttributes();
// Pull time-based restrictions for this group and verify // Pull time-based restrictions for this group and verify
String grpAllowedTimeString = grpAttributes.get(RestrictedUserGroup.RESTRICT_TIME_ALLOWED_ATTRIBUTE_NAME); String grpAllowedTimeString = grpAttributes.get(Restrictable.RESTRICT_TIME_ALLOWED_ATTRIBUTE_NAME);
String grpDeniedTimeString = grpAttributes.get(RestrictedUserGroup.RESTRICT_TIME_DENIED_ATTRIBUTE_NAME); String grpDeniedTimeString = grpAttributes.get(Restrictable.RESTRICT_TIME_DENIED_ATTRIBUTE_NAME);
RestrictionType grpRestrictionResult = allowedByTimeRestrictions(grpAllowedTimeString, grpDeniedTimeString); RestrictionType grpRestrictionResult = allowedByTimeRestrictions(grpAllowedTimeString, grpDeniedTimeString);
// An explicit deny results in immediate denial of the login. // An explicit deny results in immediate denial of the login.
@@ -463,6 +524,18 @@ public class RestrictionVerificationService {
} }
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 * Verify the time restrictions for the given Connection object, throwing
* an exception if the connection should not be allowed, or silently * an exception if the connection should not be allowed, or silently
@@ -478,8 +551,8 @@ public class RestrictionVerificationService {
public static void verifyTimeRestrictions(Restrictable restrictable) throws GuacamoleException { public static void verifyTimeRestrictions(Restrictable restrictable) throws GuacamoleException {
// Verify time-based restrictions specific to this connection. // Verify time-based restrictions specific to this connection.
String allowedTimeString = restrictable.getAttributes().get(RestrictedConnection.RESTRICT_TIME_ALLOWED_ATTRIBUTE_NAME); String allowedTimeString = restrictable.getAttributes().get(Restrictable.RESTRICT_TIME_ALLOWED_ATTRIBUTE_NAME);
String deniedTimeString = restrictable.getAttributes().get(RestrictedConnection.RESTRICT_TIME_DENIED_ATTRIBUTE_NAME); String deniedTimeString = restrictable.getAttributes().get(Restrictable.RESTRICT_TIME_DENIED_ATTRIBUTE_NAME);
RestrictionType timeRestriction = allowedByTimeRestrictions(allowedTimeString, deniedTimeString); RestrictionType timeRestriction = allowedByTimeRestrictions(allowedTimeString, deniedTimeString);
if (!timeRestriction.isAllowed()) if (!timeRestriction.isAllowed())
throw new TranslatableGuacamoleSecurityException( throw new TranslatableGuacamoleSecurityException(
@@ -536,6 +609,7 @@ public class RestrictionVerificationService {
*/ */
public static void verifyConnectionRestrictions(Restrictable restrictable, public static void verifyConnectionRestrictions(Restrictable restrictable,
String remoteAddress) throws GuacamoleException { String remoteAddress) throws GuacamoleException {
verifyDateTimeRestrictions(restrictable);
verifyTimeRestrictions(restrictable); verifyTimeRestrictions(restrictable);
verifyHostRestrictions(restrictable, remoteAddress); verifyHostRestrictions(restrictable, remoteAddress);
} }

View File

@@ -26,6 +26,7 @@ import java.util.Map;
import org.apache.guacamole.GuacamoleException; import org.apache.guacamole.GuacamoleException;
import org.apache.guacamole.auth.restrict.Restrictable; import org.apache.guacamole.auth.restrict.Restrictable;
import org.apache.guacamole.auth.restrict.RestrictionVerificationService; 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.HostRestrictionField;
import org.apache.guacamole.auth.restrict.form.TimeRestrictionField; import org.apache.guacamole.auth.restrict.form.TimeRestrictionField;
import org.apache.guacamole.calendar.RestrictionType; import org.apache.guacamole.calendar.RestrictionType;
@@ -46,49 +47,12 @@ public class RestrictedConnection extends DelegatingConnection implements Restri
*/ */
private final String remoteAddress; 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. * The list of all connection attributes provided by this Connection implementation.
*/ */
public static final List<String> RESTRICT_CONNECTION_ATTRIBUTES = Arrays.asList( public static final List<String> RESTRICT_CONNECTION_ATTRIBUTES = Arrays.asList(
RESTRICT_TIME_AFTER_ATTRIBUTE_NAME,
RESTRICT_TIME_BEFORE_ATTRIBUTE_NAME,
RESTRICT_TIME_ALLOWED_ATTRIBUTE_NAME, RESTRICT_TIME_ALLOWED_ATTRIBUTE_NAME,
RESTRICT_TIME_DENIED_ATTRIBUTE_NAME, RESTRICT_TIME_DENIED_ATTRIBUTE_NAME,
RESTRICT_HOSTS_ALLOWED_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", public static final Form RESTRICT_CONNECTION_FORM = new Form("restrict-login-form",
Arrays.asList( 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_ALLOWED_ATTRIBUTE_NAME),
new TimeRestrictionField(RESTRICT_TIME_DENIED_ATTRIBUTE_NAME), new TimeRestrictionField(RESTRICT_TIME_DENIED_ATTRIBUTE_NAME),
new HostRestrictionField(RESTRICT_HOSTS_ALLOWED_ATTRIBUTE_NAME), new HostRestrictionField(RESTRICT_HOSTS_ALLOWED_ATTRIBUTE_NAME),

View File

@@ -26,6 +26,7 @@ import java.util.Map;
import org.apache.guacamole.GuacamoleException; import org.apache.guacamole.GuacamoleException;
import org.apache.guacamole.auth.restrict.Restrictable; import org.apache.guacamole.auth.restrict.Restrictable;
import org.apache.guacamole.auth.restrict.RestrictionVerificationService; 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.HostRestrictionField;
import org.apache.guacamole.auth.restrict.form.TimeRestrictionField; import org.apache.guacamole.auth.restrict.form.TimeRestrictionField;
import org.apache.guacamole.calendar.RestrictionType; import org.apache.guacamole.calendar.RestrictionType;
@@ -46,50 +47,13 @@ public class RestrictedConnectionGroup extends DelegatingConnectionGroup impleme
*/ */
private final String remoteAddress; 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 * The list of all connection group attributes provided by this
* ConnectionGroup implementation. * ConnectionGroup implementation.
*/ */
public static final List<String> RESTRICT_CONNECTIONGROUP_ATTRIBUTES = Arrays.asList( public static final List<String> RESTRICT_CONNECTIONGROUP_ATTRIBUTES = Arrays.asList(
RESTRICT_TIME_AFTER_ATTRIBUTE_NAME,
RESTRICT_TIME_BEFORE_ATTRIBUTE_NAME,
RESTRICT_TIME_ALLOWED_ATTRIBUTE_NAME, RESTRICT_TIME_ALLOWED_ATTRIBUTE_NAME,
RESTRICT_TIME_DENIED_ATTRIBUTE_NAME, RESTRICT_TIME_DENIED_ATTRIBUTE_NAME,
RESTRICT_HOSTS_ALLOWED_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", public static final Form RESTRICT_CONNECTIONGROUP_FORM = new Form("restrict-login-form",
Arrays.asList( 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_ALLOWED_ATTRIBUTE_NAME),
new TimeRestrictionField(RESTRICT_TIME_DENIED_ATTRIBUTE_NAME), new TimeRestrictionField(RESTRICT_TIME_DENIED_ATTRIBUTE_NAME),
new HostRestrictionField(RESTRICT_HOSTS_ALLOWED_ATTRIBUTE_NAME), new HostRestrictionField(RESTRICT_HOSTS_ALLOWED_ATTRIBUTE_NAME),

View File

@@ -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);
}
}

View File

@@ -23,6 +23,7 @@ import java.util.Arrays;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; 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.HostRestrictionField;
import org.apache.guacamole.auth.restrict.form.TimeRestrictionField; import org.apache.guacamole.auth.restrict.form.TimeRestrictionField;
import org.apache.guacamole.form.Form; import org.apache.guacamole.form.Form;
@@ -33,48 +34,7 @@ import org.apache.guacamole.net.auth.UserGroup;
* UserGroup implementation which wraps a UserGroup from another extension and * UserGroup implementation which wraps a UserGroup from another extension and
* enforces additional restrictions for members of that group. * enforces additional restrictions for members of that group.
*/ */
public class RestrictedUserGroup extends DelegatingUserGroup { public class RestrictedUserGroup extends DelegatingUserGroup implements Restrictable {
/**
* 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";
/** /**
* The list of all user attributes provided by this UserGroup implementation. * The list of all user attributes provided by this UserGroup implementation.

View File

@@ -37,4 +37,11 @@ angular.module('guacRestrict').config(['formServiceProvider',
templateUrl : 'app/ext/restrict/templates/hostRestrictionField.html' 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'
});
}]); }]);

View File

@@ -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.<String, String>
*/
$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') : '');
});
}]);

View File

@@ -22,6 +22,7 @@
], ],
"resources" : { "resources" : {
"templates/dateTimeRestrictionField.html" : "text/html",
"templates/hostRestrictionField.html" : "text/html", "templates/hostRestrictionField.html" : "text/html",
"templates/timeRestrictionField.html" : "text/html" "templates/timeRestrictionField.html" : "text/html"
} }

View File

@@ -0,0 +1,12 @@
<div class="date-time-restriction-field">
<input type="datetime-local"
ng-disabled="disabled"
ng-attr-id="{{ fieldId }}"
ng-attr-name="{{ field.name }}"
ng-model="typedValue"
ng-model-options="modelOptions"
guac-focus="focused"
placeholder="{{'RESTRICT.FIELD_PLACEHOLDER_DATE_TIME_RESTRICTION' | translate}}"
autocorrect="off"
autocapitalize="off">
</div>

View File

@@ -8,7 +8,9 @@
"FIELD_HEADER_GUAC_RESTRICT_HOSTS_ALLOWED" : "Hosts from which connection may be accessed:", "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_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_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:", "FIELD_HEADER_GUAC_RESTRICT_TIME_DENIED" : "Times connection may not be used:",
"SECTION_HEADER_RESTRICT_LOGIN_FORM" : "Additional Connection Restrictions" "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_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_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_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:", "FIELD_HEADER_GUAC_RESTRICT_TIME_DENIED" : "Times connection group may not be used:",
"SECTION_HEADER_RESTRICT_LOGIN_FORM" : "Additional Connection Restrictions" "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_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.", "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_DAY" : "Day",
"TABLE_HEADER_END_TIME" : "End Time", "TABLE_HEADER_END_TIME" : "End Time",
"TABLE_HEADER_HOST" : "Host", "TABLE_HEADER_HOST" : "Host",