mirror of
https://github.com/gyurix1968/guacamole-client.git
synced 2025-09-06 13:17:41 +00:00
GUACAMOLE-36: Merge password policy support.
This commit is contained in:
@@ -63,6 +63,7 @@ import org.apache.guacamole.auth.jdbc.connection.ConnectionParameterMapper;
|
||||
import org.apache.guacamole.auth.jdbc.permission.SharingProfilePermissionMapper;
|
||||
import org.apache.guacamole.auth.jdbc.permission.SharingProfilePermissionService;
|
||||
import org.apache.guacamole.auth.jdbc.permission.SharingProfilePermissionSet;
|
||||
import org.apache.guacamole.auth.jdbc.security.PasswordPolicyService;
|
||||
import org.apache.guacamole.auth.jdbc.sharing.ConnectionSharingService;
|
||||
import org.apache.guacamole.auth.jdbc.sharing.HashSharedConnectionMap;
|
||||
import org.apache.guacamole.auth.jdbc.sharing.SecureRandomShareKeyGenerator;
|
||||
@@ -159,6 +160,7 @@ public class JDBCAuthenticationProviderModule extends MyBatisModule {
|
||||
bind(ConnectionService.class);
|
||||
bind(GuacamoleTunnelService.class).to(RestrictedGuacamoleTunnelService.class);
|
||||
bind(PasswordEncryptionService.class).to(SHA256PasswordEncryptionService.class);
|
||||
bind(PasswordPolicyService.class);
|
||||
bind(SaltService.class).to(SecureRandomSaltService.class);
|
||||
bind(SharedConnectionMap.class).to(HashSharedConnectionMap.class).in(Scopes.SINGLETON);
|
||||
bind(ShareKeyGenerator.class).to(SecureRandomShareKeyGenerator.class).in(Scopes.SINGLETON);
|
||||
|
@@ -21,6 +21,7 @@ package org.apache.guacamole.auth.jdbc;
|
||||
|
||||
import org.apache.guacamole.GuacamoleException;
|
||||
import org.apache.guacamole.environment.LocalEnvironment;
|
||||
import org.apache.guacamole.auth.jdbc.security.PasswordPolicy;
|
||||
|
||||
/**
|
||||
* A JDBC-specific implementation of Environment that defines generic properties
|
||||
@@ -128,4 +129,14 @@ public abstract class JDBCEnvironment extends LocalEnvironment {
|
||||
public abstract int getDefaultMaxGroupConnectionsPerUser()
|
||||
throws GuacamoleException;
|
||||
|
||||
/**
|
||||
* Returns the policy which applies to newly-set passwords. Passwords which
|
||||
* apply to Guacamole user accounts will be required to conform to this
|
||||
* policy.
|
||||
*
|
||||
* @return
|
||||
* The password policy which applies to Guacamole user accounts.
|
||||
*/
|
||||
public abstract PasswordPolicy getPasswordPolicy();
|
||||
|
||||
}
|
||||
|
@@ -172,9 +172,9 @@ public abstract class ModeledChildDirectoryObjectService<InternalType extends Mo
|
||||
|
||||
@Override
|
||||
protected void beforeCreate(ModeledAuthenticatedUser user,
|
||||
ModelType model) throws GuacamoleException {
|
||||
ExternalType object, ModelType model) throws GuacamoleException {
|
||||
|
||||
super.beforeCreate(user, model);
|
||||
super.beforeCreate(user, object, model);
|
||||
|
||||
// Validate that we can update all applicable parents
|
||||
if (!canUpdateModifiedParents(user, null, model))
|
||||
@@ -184,9 +184,9 @@ public abstract class ModeledChildDirectoryObjectService<InternalType extends Mo
|
||||
|
||||
@Override
|
||||
protected void beforeUpdate(ModeledAuthenticatedUser user,
|
||||
ModelType model) throws GuacamoleException {
|
||||
InternalType object, ModelType model) throws GuacamoleException {
|
||||
|
||||
super.beforeUpdate(user, model);
|
||||
super.beforeUpdate(user, object, model);
|
||||
|
||||
// Validate that we can update all applicable parents
|
||||
if (!canUpdateModifiedParents(user, model.getIdentifier(), model))
|
||||
|
@@ -222,6 +222,9 @@ public abstract class ModeledDirectoryObjectService<InternalType extends Modeled
|
||||
* @param user
|
||||
* The user creating the object.
|
||||
*
|
||||
* @param object
|
||||
* The object being created.
|
||||
*
|
||||
* @param model
|
||||
* The model of the object being created.
|
||||
*
|
||||
@@ -230,7 +233,7 @@ public abstract class ModeledDirectoryObjectService<InternalType extends Modeled
|
||||
* object.
|
||||
*/
|
||||
protected void beforeCreate(ModeledAuthenticatedUser user,
|
||||
ModelType model ) throws GuacamoleException {
|
||||
ExternalType object, ModelType model) throws GuacamoleException {
|
||||
|
||||
// Verify permission to create objects
|
||||
if (!user.getUser().isAdministrator() && !hasCreatePermission(user))
|
||||
@@ -247,6 +250,9 @@ public abstract class ModeledDirectoryObjectService<InternalType extends Modeled
|
||||
* @param user
|
||||
* The user updating the existing object.
|
||||
*
|
||||
* @param object
|
||||
* The object being updated.
|
||||
*
|
||||
* @param model
|
||||
* The model of the object being updated.
|
||||
*
|
||||
@@ -255,7 +261,7 @@ public abstract class ModeledDirectoryObjectService<InternalType extends Modeled
|
||||
* object.
|
||||
*/
|
||||
protected void beforeUpdate(ModeledAuthenticatedUser user,
|
||||
ModelType model) throws GuacamoleException {
|
||||
InternalType object, ModelType model) throws GuacamoleException {
|
||||
|
||||
// By default, do nothing.
|
||||
if (!hasObjectPermission(user, model.getIdentifier(), ObjectPermission.Type.UPDATE))
|
||||
@@ -436,7 +442,7 @@ public abstract class ModeledDirectoryObjectService<InternalType extends Modeled
|
||||
throws GuacamoleException {
|
||||
|
||||
ModelType model = getModelInstance(user, object);
|
||||
beforeCreate(user, model);
|
||||
beforeCreate(user, object, model);
|
||||
|
||||
// Create object
|
||||
getObjectMapper().insert(model);
|
||||
@@ -467,7 +473,7 @@ public abstract class ModeledDirectoryObjectService<InternalType extends Modeled
|
||||
throws GuacamoleException {
|
||||
|
||||
ModelType model = object.getModel();
|
||||
beforeUpdate(user, model);
|
||||
beforeUpdate(user, object, model);
|
||||
|
||||
// Update object
|
||||
getObjectMapper().update(model);
|
||||
|
@@ -156,9 +156,10 @@ public class ConnectionService extends ModeledChildDirectoryObjectService<Modele
|
||||
|
||||
@Override
|
||||
protected void beforeCreate(ModeledAuthenticatedUser user,
|
||||
ConnectionModel model) throws GuacamoleException {
|
||||
Connection object, ConnectionModel model)
|
||||
throws GuacamoleException {
|
||||
|
||||
super.beforeCreate(user, model);
|
||||
super.beforeCreate(user, object, model);
|
||||
|
||||
// Name must not be blank
|
||||
if (model.getName() == null || model.getName().trim().isEmpty())
|
||||
@@ -173,9 +174,10 @@ public class ConnectionService extends ModeledChildDirectoryObjectService<Modele
|
||||
|
||||
@Override
|
||||
protected void beforeUpdate(ModeledAuthenticatedUser user,
|
||||
ConnectionModel model) throws GuacamoleException {
|
||||
ModeledConnection object, ConnectionModel model)
|
||||
throws GuacamoleException {
|
||||
|
||||
super.beforeUpdate(user, model);
|
||||
super.beforeUpdate(user, object, model);
|
||||
|
||||
// Name must not be blank
|
||||
if (model.getName() == null || model.getName().trim().isEmpty())
|
||||
|
@@ -139,9 +139,10 @@ public class ConnectionGroupService extends ModeledChildDirectoryObjectService<M
|
||||
|
||||
@Override
|
||||
protected void beforeCreate(ModeledAuthenticatedUser user,
|
||||
ConnectionGroupModel model) throws GuacamoleException {
|
||||
ConnectionGroup object, ConnectionGroupModel model)
|
||||
throws GuacamoleException {
|
||||
|
||||
super.beforeCreate(user, model);
|
||||
super.beforeCreate(user, object, model);
|
||||
|
||||
// Name must not be blank
|
||||
if (model.getName() == null || model.getName().trim().isEmpty())
|
||||
@@ -156,9 +157,10 @@ public class ConnectionGroupService extends ModeledChildDirectoryObjectService<M
|
||||
|
||||
@Override
|
||||
protected void beforeUpdate(ModeledAuthenticatedUser user,
|
||||
ConnectionGroupModel model) throws GuacamoleException {
|
||||
ModeledConnectionGroup object, ConnectionGroupModel model)
|
||||
throws GuacamoleException {
|
||||
|
||||
super.beforeUpdate(user, model);
|
||||
super.beforeUpdate(user, object, model);
|
||||
|
||||
// Name must not be blank
|
||||
if (model.getName() == null || model.getName().trim().isEmpty())
|
||||
|
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* 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.jdbc.security;
|
||||
|
||||
/**
|
||||
* Thrown when an attempt is made to set a user's password to a string which
|
||||
* contains their own username, in violation of the defined password policy.
|
||||
*
|
||||
* @author Michael Jumper
|
||||
*/
|
||||
public class PasswordContainsUsernameException extends PasswordPolicyException {
|
||||
|
||||
/**
|
||||
* Creates a new PasswordContainsUsernameException with the given
|
||||
* human-readable message. The translatable message is already defined.
|
||||
*
|
||||
* @param message
|
||||
* A human-readable message describing the password policy violation
|
||||
* that occurred.
|
||||
*/
|
||||
public PasswordContainsUsernameException(String message) {
|
||||
super(message, "PASSWORD_POLICY.ERROR_CONTAINS_USERNAME");
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* 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.jdbc.security;
|
||||
|
||||
import java.util.Collections;
|
||||
import org.apache.guacamole.language.TranslatableMessage;
|
||||
|
||||
/**
|
||||
* Thrown when an attempt is made to set a user's password to a string which is
|
||||
* too short, in violation of the defined password policy.
|
||||
*
|
||||
* @author Michael Jumper
|
||||
*/
|
||||
public class PasswordMinimumLengthException extends PasswordPolicyException {
|
||||
|
||||
/**
|
||||
* Creates a new PasswordMinimumLengthException with the given
|
||||
* human-readable message. The translatable message is already defined.
|
||||
*
|
||||
* @param message
|
||||
* A human-readable message describing the password policy violation
|
||||
* that occurred.
|
||||
*
|
||||
* @param length
|
||||
* The minimum length that passwords must have to avoid violating
|
||||
* policy, in characters.
|
||||
*/
|
||||
public PasswordMinimumLengthException(String message, int length) {
|
||||
super(message, new TranslatableMessage(
|
||||
"PASSWORD_POLICY.ERROR_TOO_SHORT",
|
||||
Collections.singletonMap("LENGTH", length)
|
||||
));
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,103 @@
|
||||
/*
|
||||
* 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.jdbc.security;
|
||||
|
||||
import org.apache.guacamole.GuacamoleException;
|
||||
|
||||
/**
|
||||
* A set of restrictions which define the level of complexity required for
|
||||
* the passwords of Guacamole user accounts.
|
||||
*
|
||||
* @author Michael Jumper
|
||||
*/
|
||||
public interface PasswordPolicy {
|
||||
|
||||
/**
|
||||
* Returns the minimum length of new passwords, in characters. Passwords
|
||||
* which are shorter than this length cannot be used.
|
||||
*
|
||||
* @return
|
||||
* The minimum number of characters required for new passwords.
|
||||
*
|
||||
* @throws GuacamoleException
|
||||
* If the minimum password length cannot be parsed from
|
||||
* guacamole.properties.
|
||||
*/
|
||||
int getMinimumLength() throws GuacamoleException;
|
||||
|
||||
/**
|
||||
* Returns whether both uppercase and lowercase characters must be present
|
||||
* in new passwords. If true, passwords which do not have at least one
|
||||
* uppercase letter and one lowercase letter cannot be used.
|
||||
*
|
||||
* @return
|
||||
* true if both uppercase and lowercase characters must be present in
|
||||
* new passwords, false otherwise.
|
||||
*
|
||||
* @throws GuacamoleException
|
||||
* If the multiple case requirement cannot be parsed from
|
||||
* guacamole.properties.
|
||||
*/
|
||||
boolean isMultipleCaseRequired() throws GuacamoleException;
|
||||
|
||||
/**
|
||||
* Returns whether numeric characters (digits) must be present in new
|
||||
* passwords. If true, passwords which do not have at least one numeric
|
||||
* character cannot be used.
|
||||
*
|
||||
* @return
|
||||
* true if numeric characters must be present in new passwords,
|
||||
* false otherwise.
|
||||
*
|
||||
* @throws GuacamoleException
|
||||
* If the numeric character requirement cannot be parsed from
|
||||
* guacamole.properties.
|
||||
*/
|
||||
boolean isNumericRequired() throws GuacamoleException;
|
||||
|
||||
/**
|
||||
* Returns whether non-alphanumeric characters (symbols) must be present in
|
||||
* new passwords. If true, passwords which do not have at least one
|
||||
* non-alphanumeric character cannot be used.
|
||||
*
|
||||
* @return
|
||||
* true if non-alphanumeric characters must be present in new passwords,
|
||||
* false otherwise.
|
||||
*
|
||||
* @throws GuacamoleException
|
||||
* If the non-alphanumeric character requirement cannot be parsed from
|
||||
* guacamole.properties.
|
||||
*/
|
||||
boolean isNonAlphanumericRequired() throws GuacamoleException;
|
||||
|
||||
/**
|
||||
* Returns whether new passwords must not contain the user's own username.
|
||||
*
|
||||
* @return
|
||||
* true if new passwords must not contain the user's own username,
|
||||
* false otherwise.
|
||||
*
|
||||
* @throws GuacamoleException
|
||||
* If the username password restriction cannot be parsed from
|
||||
* guacamole.properties.
|
||||
*/
|
||||
boolean isUsernameProhibited() throws GuacamoleException;
|
||||
|
||||
}
|
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* 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.jdbc.security;
|
||||
|
||||
import org.apache.guacamole.GuacamoleClientException;
|
||||
import org.apache.guacamole.language.Translatable;
|
||||
import org.apache.guacamole.language.TranslatableMessage;
|
||||
|
||||
/**
|
||||
* Thrown when an attempt to change a user's password fails due to a violation
|
||||
* of password complexity policies.
|
||||
*
|
||||
* @author Michael Jumper
|
||||
*/
|
||||
public class PasswordPolicyException extends GuacamoleClientException
|
||||
implements Translatable {
|
||||
|
||||
/**
|
||||
* A translatable message which, after being passed through the translation
|
||||
* system, describes the policy violation that occurred.
|
||||
*/
|
||||
private final TranslatableMessage translatableMessage;
|
||||
|
||||
/**
|
||||
* Creates a new PasswordPolicyException with the given human-readable
|
||||
* message (which will not be passed through the translation system) and
|
||||
* translation string key(which WILL be passed through the translation
|
||||
* system), both of which should describe the policy violation that
|
||||
* occurred.
|
||||
*
|
||||
* @param message
|
||||
* A human-readable message describing the policy violation that
|
||||
* occurred.
|
||||
*
|
||||
* @param translationKey
|
||||
* The key of a translation string known to the translation system
|
||||
* which describes the policy violation that occurred.
|
||||
*/
|
||||
public PasswordPolicyException(String message, String translationKey) {
|
||||
super(message);
|
||||
this.translatableMessage = new TranslatableMessage(translationKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new PasswordPolicyException with the given human-readable
|
||||
* message (which will not be passed through the translation system) and
|
||||
* translatable message (which WILL be passed through the translation
|
||||
* system), both of which should describe the policy violation that
|
||||
* occurred.
|
||||
*
|
||||
* @param message
|
||||
* A human-readable message describing the policy violation that
|
||||
* occurred.
|
||||
*
|
||||
* @param translatableMessage
|
||||
* A translatable message which, after being passed through the
|
||||
* translation system, describes the policy violation that occurred.
|
||||
*/
|
||||
public PasswordPolicyException(String message, TranslatableMessage translatableMessage) {
|
||||
super(message);
|
||||
this.translatableMessage = translatableMessage;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TranslatableMessage getTranslatableMessage() {
|
||||
return translatableMessage;
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,149 @@
|
||||
/*
|
||||
* 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.jdbc.security;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import org.apache.guacamole.GuacamoleException;
|
||||
import org.apache.guacamole.auth.jdbc.JDBCEnvironment;
|
||||
|
||||
/**
|
||||
* Service which verifies compliance with the password policy configured via
|
||||
* guacamole.properties.
|
||||
*
|
||||
* @author Michael Jumper
|
||||
*/
|
||||
public class PasswordPolicyService {
|
||||
|
||||
/**
|
||||
* The Guacamole server environment.
|
||||
*/
|
||||
@Inject
|
||||
private JDBCEnvironment environment;
|
||||
|
||||
/**
|
||||
* Regular expression which matches only if the string contains at least one
|
||||
* lowercase character.
|
||||
*/
|
||||
private final Pattern CONTAINS_LOWERCASE = Pattern.compile("\\p{javaLowerCase}");
|
||||
|
||||
/**
|
||||
* Regular expression which matches only if the string contains at least one
|
||||
* uppercase character.
|
||||
*/
|
||||
private final Pattern CONTAINS_UPPERCASE = Pattern.compile("\\p{javaUpperCase}");
|
||||
|
||||
/**
|
||||
* Regular expression which matches only if the string contains at least one
|
||||
* numeric character.
|
||||
*/
|
||||
private final Pattern CONTAINS_DIGIT = Pattern.compile("\\p{Digit}");
|
||||
|
||||
/**
|
||||
* Regular expression which matches only if the string contains at least one
|
||||
* non-alphanumeric character.
|
||||
*/
|
||||
private final Pattern CONTAINS_NON_ALPHANUMERIC =
|
||||
Pattern.compile("[^\\p{javaLowerCase}\\p{javaUpperCase}\\p{Digit}]");
|
||||
|
||||
/**
|
||||
* Returns whether the given string matches all of the provided regular
|
||||
* expressions.
|
||||
*
|
||||
* @param str
|
||||
* The string to test against all provided regular expressions.
|
||||
*
|
||||
* @param patterns
|
||||
* The regular expressions to match against the given string.
|
||||
*
|
||||
* @return
|
||||
* true if the given string matches all provided regular expressions,
|
||||
* false otherwise.
|
||||
*/
|
||||
private boolean matches(String str, Pattern... patterns) {
|
||||
|
||||
// Check given string against all provided patterns
|
||||
for (Pattern pattern : patterns) {
|
||||
|
||||
// Fail overall test if any pattern fails to match
|
||||
Matcher matcher = pattern.matcher(str);
|
||||
if (!matcher.find())
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
// All provided patterns matched
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies that the given new password complies with the password policy
|
||||
* configured within guacamole.properties, throwing a GuacamoleException if
|
||||
* the policy is violated in any way.
|
||||
*
|
||||
* @param username
|
||||
* The username of the user whose password is being changed.
|
||||
*
|
||||
* @param password
|
||||
* The proposed new password.
|
||||
*
|
||||
* @throws GuacamoleException
|
||||
* If the password policy cannot be parsed, or if the proposed password
|
||||
* violates the password policy.
|
||||
*/
|
||||
public void verifyPassword(String username, String password)
|
||||
throws GuacamoleException {
|
||||
|
||||
// Retrieve password policy from environment
|
||||
PasswordPolicy policy = environment.getPasswordPolicy();
|
||||
|
||||
// Enforce minimum password length
|
||||
if (password.length() < policy.getMinimumLength())
|
||||
throw new PasswordMinimumLengthException(
|
||||
"Password does not meet minimum length requirements.",
|
||||
policy.getMinimumLength());
|
||||
|
||||
// Disallow passwords containing the username
|
||||
if (policy.isUsernameProhibited() && password.toLowerCase().contains(username.toLowerCase()))
|
||||
throw new PasswordContainsUsernameException(
|
||||
"Password must not contain username.");
|
||||
|
||||
// Require both uppercase and lowercase characters
|
||||
if (policy.isMultipleCaseRequired() && !matches(password, CONTAINS_LOWERCASE, CONTAINS_UPPERCASE))
|
||||
throw new PasswordRequiresMultipleCaseException(
|
||||
"Password must contain both uppercase and lowercase.");
|
||||
|
||||
// Require digits
|
||||
if (policy.isNumericRequired() && !matches(password, CONTAINS_DIGIT))
|
||||
throw new PasswordRequiresDigitException(
|
||||
"Passwords must contain at least one digit.");
|
||||
|
||||
// Require non-alphanumeric symbols
|
||||
if (policy.isNonAlphanumericRequired() && !matches(password, CONTAINS_NON_ALPHANUMERIC))
|
||||
throw new PasswordRequiresSymbolException(
|
||||
"Passwords must contain at least one non-alphanumeric character.");
|
||||
|
||||
// Password passes all defined restrictions
|
||||
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* 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.jdbc.security;
|
||||
|
||||
/**
|
||||
* Thrown when an attempt is made to set a user's password to a string which
|
||||
* contains no numeric characters (digits), in violation of the defined password
|
||||
* policy.
|
||||
*
|
||||
* @author Michael Jumper
|
||||
*/
|
||||
public class PasswordRequiresDigitException extends PasswordPolicyException {
|
||||
|
||||
/**
|
||||
* Creates a new PasswordRequiresDigitException with the given
|
||||
* human-readable message. The translatable message is already defined.
|
||||
*
|
||||
* @param message
|
||||
* A human-readable message describing the password policy violation
|
||||
* that occurred.
|
||||
*/
|
||||
public PasswordRequiresDigitException(String message) {
|
||||
super(message, "PASSWORD_POLICY.ERROR_REQUIRES_DIGIT");
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* 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.jdbc.security;
|
||||
|
||||
/**
|
||||
* Thrown when an attempt is made to set a user's password to a string which
|
||||
* does not contain both uppercase and lowercase characters, in violation of the
|
||||
* defined password policy.
|
||||
*
|
||||
* @author Michael Jumper
|
||||
*/
|
||||
public class PasswordRequiresMultipleCaseException extends PasswordPolicyException {
|
||||
|
||||
/**
|
||||
* Creates a new PasswordRequiresMultipleCaseException with the given
|
||||
* human-readable message. The translatable message is already defined.
|
||||
*
|
||||
* @param message
|
||||
* A human-readable message describing the password policy violation
|
||||
* that occurred.
|
||||
*/
|
||||
public PasswordRequiresMultipleCaseException(String message) {
|
||||
super(message, "PASSWORD_POLICY.ERROR_REQUIRES_MULTIPLE_CASE");
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* 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.jdbc.security;
|
||||
|
||||
/**
|
||||
* Thrown when an attempt is made to set a user's password to a string which
|
||||
* contains no non-alphanumeric characters (symbols), in violation of the
|
||||
* defined password policy.
|
||||
*
|
||||
* @author Michael Jumper
|
||||
*/
|
||||
public class PasswordRequiresSymbolException extends PasswordPolicyException {
|
||||
|
||||
/**
|
||||
* Creates a new PasswordRequiresSymbolException with the given
|
||||
* human-readable message. The translatable message is already defined.
|
||||
*
|
||||
* @param message
|
||||
* A human-readable message describing the password policy violation
|
||||
* that occurred.
|
||||
*/
|
||||
public PasswordRequiresSymbolException(String message) {
|
||||
super(message, "PASSWORD_POLICY.ERROR_REQUIRES_NON_ALNUM");
|
||||
}
|
||||
|
||||
}
|
@@ -139,9 +139,10 @@ public class SharingProfileService
|
||||
|
||||
@Override
|
||||
protected void beforeCreate(ModeledAuthenticatedUser user,
|
||||
SharingProfileModel model) throws GuacamoleException {
|
||||
SharingProfile object, SharingProfileModel model)
|
||||
throws GuacamoleException {
|
||||
|
||||
super.beforeCreate(user, model);
|
||||
super.beforeCreate(user, object, model);
|
||||
|
||||
// Name must not be blank
|
||||
if (model.getName() == null || model.getName().trim().isEmpty())
|
||||
@@ -156,9 +157,10 @@ public class SharingProfileService
|
||||
|
||||
@Override
|
||||
protected void beforeUpdate(ModeledAuthenticatedUser user,
|
||||
SharingProfileModel model) throws GuacamoleException {
|
||||
ModeledSharingProfile object, SharingProfileModel model)
|
||||
throws GuacamoleException {
|
||||
|
||||
super.beforeUpdate(user, model);
|
||||
super.beforeUpdate(user, object, model);
|
||||
|
||||
// Name must not be blank
|
||||
if (model.getName() == null || model.getName().trim().isEmpty())
|
||||
|
@@ -206,10 +206,10 @@ public class ModeledUser extends ModeledDirectoryObject<UserModel> implements Us
|
||||
// Store plaintext password internally
|
||||
this.password = password;
|
||||
|
||||
// If no password provided, clear password salt and hash
|
||||
// If no password provided, set random password
|
||||
if (password == null) {
|
||||
userModel.setPasswordSalt(null);
|
||||
userModel.setPasswordHash(null);
|
||||
userModel.setPasswordSalt(saltService.generateSalt());
|
||||
userModel.setPasswordHash(saltService.generateSalt());
|
||||
}
|
||||
|
||||
// Otherwise generate new salt and hash given password using newly-generated salt
|
||||
|
@@ -35,6 +35,7 @@ import org.apache.guacamole.auth.jdbc.permission.ObjectPermissionMapper;
|
||||
import org.apache.guacamole.auth.jdbc.permission.ObjectPermissionModel;
|
||||
import org.apache.guacamole.auth.jdbc.permission.UserPermissionMapper;
|
||||
import org.apache.guacamole.auth.jdbc.security.PasswordEncryptionService;
|
||||
import org.apache.guacamole.auth.jdbc.security.PasswordPolicyService;
|
||||
import org.apache.guacamole.form.Field;
|
||||
import org.apache.guacamole.form.PasswordField;
|
||||
import org.apache.guacamole.net.auth.AuthenticatedUser;
|
||||
@@ -130,6 +131,12 @@ public class UserService extends ModeledDirectoryObjectService<ModeledUser, User
|
||||
@Inject
|
||||
private PasswordEncryptionService encryptionService;
|
||||
|
||||
/**
|
||||
* Service for enforcing password complexity policies.
|
||||
*/
|
||||
@Inject
|
||||
private PasswordPolicyService passwordPolicyService;
|
||||
|
||||
@Override
|
||||
protected ModeledDirectoryObjectMapper<UserModel> getObjectMapper() {
|
||||
return userMapper;
|
||||
@@ -185,10 +192,10 @@ public class UserService extends ModeledDirectoryObjectService<ModeledUser, User
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void beforeCreate(ModeledAuthenticatedUser user, UserModel model)
|
||||
throws GuacamoleException {
|
||||
protected void beforeCreate(ModeledAuthenticatedUser user, User object,
|
||||
UserModel model) throws GuacamoleException {
|
||||
|
||||
super.beforeCreate(user, model);
|
||||
super.beforeCreate(user, object, model);
|
||||
|
||||
// Username must not be blank
|
||||
if (model.getIdentifier() == null || model.getIdentifier().trim().isEmpty())
|
||||
@@ -199,13 +206,17 @@ public class UserService extends ModeledDirectoryObjectService<ModeledUser, User
|
||||
if (!existing.isEmpty())
|
||||
throw new GuacamoleClientException("User \"" + model.getIdentifier() + "\" already exists.");
|
||||
|
||||
// Verify new password does not violate defined policies (if specified)
|
||||
if (object.getPassword() != null)
|
||||
passwordPolicyService.verifyPassword(object.getIdentifier(), object.getPassword());
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void beforeUpdate(ModeledAuthenticatedUser user,
|
||||
UserModel model) throws GuacamoleException {
|
||||
ModeledUser object, UserModel model) throws GuacamoleException {
|
||||
|
||||
super.beforeUpdate(user, model);
|
||||
super.beforeUpdate(user, object, model);
|
||||
|
||||
// Username must not be blank
|
||||
if (model.getIdentifier() == null || model.getIdentifier().trim().isEmpty())
|
||||
@@ -221,6 +232,10 @@ public class UserService extends ModeledDirectoryObjectService<ModeledUser, User
|
||||
|
||||
}
|
||||
|
||||
// Verify new password does not violate defined policies (if specified)
|
||||
if (object.getPassword() != null)
|
||||
passwordPolicyService.verifyPassword(object.getIdentifier(), object.getPassword());
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -412,6 +427,9 @@ public class UserService extends ModeledDirectoryObjectService<ModeledUser, User
|
||||
if (!newPassword.equals(confirmNewPassword))
|
||||
throw new GuacamoleClientException("LOGIN.ERROR_PASSWORD_MISMATCH");
|
||||
|
||||
// Verify new password does not violate defined policies
|
||||
passwordPolicyService.verifyPassword(username, newPassword);
|
||||
|
||||
// Change password and reset expiration flag
|
||||
userModel.setExpired(false);
|
||||
user.setPassword(newPassword);
|
||||
|
@@ -54,6 +54,16 @@
|
||||
"INFO_SHARED_BY" : "Shared by {USERNAME}"
|
||||
},
|
||||
|
||||
"PASSWORD_POLICY" : {
|
||||
|
||||
"ERROR_CONTAINS_USERNAME" : "Passwords may not contain the username.",
|
||||
"ERROR_REQUIRES_DIGIT" : "Passwords must contain at least one digit.",
|
||||
"ERROR_REQUIRES_MULTIPLE_CASE" : "Passwords must contain both uppercase and lowercase characters.",
|
||||
"ERROR_REQUIRES_NON_ALNUM" : "Passwords must contain at least one symbol.",
|
||||
"ERROR_TOO_SHORT" : "Passwords must be at least {LENGTH} {LENGTH, plural, one{character} other{characters}} long."
|
||||
|
||||
},
|
||||
|
||||
"USER_ATTRIBUTES" : {
|
||||
|
||||
"FIELD_HEADER_DISABLED" : "Login disabled:",
|
||||
|
@@ -23,6 +23,7 @@ import org.apache.guacamole.GuacamoleException;
|
||||
import org.apache.guacamole.auth.jdbc.JDBCEnvironment;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.apache.guacamole.auth.jdbc.security.PasswordPolicy;
|
||||
|
||||
/**
|
||||
* A MySQL-specific implementation of JDBCEnvironment provides database
|
||||
@@ -220,6 +221,11 @@ public class MySQLEnvironment extends JDBCEnvironment {
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PasswordPolicy getPasswordPolicy() {
|
||||
return new MySQLPasswordPolicy(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the hostname of the MySQL server hosting the Guacamole
|
||||
* authentication tables. If unspecified, this will be "localhost".
|
||||
|
@@ -0,0 +1,142 @@
|
||||
/*
|
||||
* 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.mysql;
|
||||
|
||||
import org.apache.guacamole.GuacamoleException;
|
||||
import org.apache.guacamole.auth.jdbc.JDBCEnvironment;
|
||||
import org.apache.guacamole.auth.jdbc.security.PasswordPolicy;
|
||||
import org.apache.guacamole.properties.BooleanGuacamoleProperty;
|
||||
import org.apache.guacamole.properties.IntegerGuacamoleProperty;
|
||||
|
||||
/**
|
||||
* PasswordPolicy implementation which reads the details of the policy from
|
||||
* MySQL-specific properties in guacamole.properties.
|
||||
*
|
||||
* @author Michael Jumper
|
||||
*/
|
||||
public class MySQLPasswordPolicy implements PasswordPolicy {
|
||||
|
||||
/**
|
||||
* The property which specifies the minimum length required of all user
|
||||
* passwords. By default, this will be zero.
|
||||
*/
|
||||
private static final IntegerGuacamoleProperty MIN_LENGTH =
|
||||
new IntegerGuacamoleProperty() {
|
||||
|
||||
@Override
|
||||
public String getName() { return "mysql-user-password-min-length"; }
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* The property which specifies whether all user passwords must have at
|
||||
* least one lowercase character and one uppercase character. By default,
|
||||
* no such restriction is imposed.
|
||||
*/
|
||||
private static final BooleanGuacamoleProperty REQUIRE_MULTIPLE_CASE =
|
||||
new BooleanGuacamoleProperty() {
|
||||
|
||||
@Override
|
||||
public String getName() { return "mysql-user-password-require-multiple-case"; }
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* The property which specifies whether all user passwords must have at
|
||||
* least one numeric character (digit). By default, no such restriction is
|
||||
* imposed.
|
||||
*/
|
||||
private static final BooleanGuacamoleProperty REQUIRE_DIGIT =
|
||||
new BooleanGuacamoleProperty() {
|
||||
|
||||
@Override
|
||||
public String getName() { return "mysql-user-password-require-digit"; }
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* The property which specifies whether all user passwords must have at
|
||||
* least one non-alphanumeric character (symbol). By default, no such
|
||||
* restriction is imposed.
|
||||
*/
|
||||
private static final BooleanGuacamoleProperty REQUIRE_SYMBOL =
|
||||
new BooleanGuacamoleProperty() {
|
||||
|
||||
@Override
|
||||
public String getName() { return "mysql-user-password-require-symbol"; }
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* The property which specifies whether users are prohibited from including
|
||||
* their own username in their password. By default, no such restriction is
|
||||
* imposed.
|
||||
*/
|
||||
private static final BooleanGuacamoleProperty PROHIBIT_USERNAME =
|
||||
new BooleanGuacamoleProperty() {
|
||||
|
||||
@Override
|
||||
public String getName() { return "mysql-user-password-prohibit-username"; }
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* The Guacamole server environment.
|
||||
*/
|
||||
private final JDBCEnvironment environment;
|
||||
|
||||
/**
|
||||
* Creates a new MySQLPasswordPolicy which reads the details of the policy
|
||||
* from the properties exposed by the given environment.
|
||||
*
|
||||
* @param environment
|
||||
* The environment from which password policy properties should be
|
||||
* read.
|
||||
*/
|
||||
public MySQLPasswordPolicy(JDBCEnvironment environment) {
|
||||
this.environment = environment;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMinimumLength() throws GuacamoleException {
|
||||
return environment.getProperty(MIN_LENGTH, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isMultipleCaseRequired() throws GuacamoleException {
|
||||
return environment.getProperty(REQUIRE_MULTIPLE_CASE, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isNumericRequired() throws GuacamoleException {
|
||||
return environment.getProperty(REQUIRE_DIGIT, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isNonAlphanumericRequired() throws GuacamoleException {
|
||||
return environment.getProperty(REQUIRE_SYMBOL, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isUsernameProhibited() throws GuacamoleException {
|
||||
return environment.getProperty(PROHIBIT_USERNAME, false);
|
||||
}
|
||||
|
||||
}
|
@@ -23,6 +23,7 @@ import org.apache.guacamole.GuacamoleException;
|
||||
import org.apache.guacamole.auth.jdbc.JDBCEnvironment;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.apache.guacamole.auth.jdbc.security.PasswordPolicy;
|
||||
|
||||
/**
|
||||
* A PostgreSQL-specific implementation of JDBCEnvironment provides database
|
||||
@@ -219,6 +220,11 @@ public class PostgreSQLEnvironment extends JDBCEnvironment {
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PasswordPolicy getPasswordPolicy() {
|
||||
return new PostgreSQLPasswordPolicy(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the hostname of the PostgreSQL server hosting the Guacamole
|
||||
* authentication tables. If unspecified, this will be "localhost".
|
||||
|
@@ -0,0 +1,142 @@
|
||||
/*
|
||||
* 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.postgresql;
|
||||
|
||||
import org.apache.guacamole.GuacamoleException;
|
||||
import org.apache.guacamole.auth.jdbc.JDBCEnvironment;
|
||||
import org.apache.guacamole.auth.jdbc.security.PasswordPolicy;
|
||||
import org.apache.guacamole.properties.BooleanGuacamoleProperty;
|
||||
import org.apache.guacamole.properties.IntegerGuacamoleProperty;
|
||||
|
||||
/**
|
||||
* PasswordPolicy implementation which reads the details of the policy from
|
||||
* PostgreSQL-specific properties in guacamole.properties.
|
||||
*
|
||||
* @author Michael Jumper
|
||||
*/
|
||||
public class PostgreSQLPasswordPolicy implements PasswordPolicy {
|
||||
|
||||
/**
|
||||
* The property which specifies the minimum length required of all user
|
||||
* passwords. By default, this will be zero.
|
||||
*/
|
||||
private static final IntegerGuacamoleProperty MIN_LENGTH =
|
||||
new IntegerGuacamoleProperty() {
|
||||
|
||||
@Override
|
||||
public String getName() { return "postgresql-user-password-min-length"; }
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* The property which specifies whether all user passwords must have at
|
||||
* least one lowercase character and one uppercase character. By default,
|
||||
* no such restriction is imposed.
|
||||
*/
|
||||
private static final BooleanGuacamoleProperty REQUIRE_MULTIPLE_CASE =
|
||||
new BooleanGuacamoleProperty() {
|
||||
|
||||
@Override
|
||||
public String getName() { return "postgresql-user-password-require-multiple-case"; }
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* The property which specifies whether all user passwords must have at
|
||||
* least one numeric character (digit). By default, no such restriction is
|
||||
* imposed.
|
||||
*/
|
||||
private static final BooleanGuacamoleProperty REQUIRE_DIGIT =
|
||||
new BooleanGuacamoleProperty() {
|
||||
|
||||
@Override
|
||||
public String getName() { return "postgresql-user-password-require-digit"; }
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* The property which specifies whether all user passwords must have at
|
||||
* least one non-alphanumeric character (symbol). By default, no such
|
||||
* restriction is imposed.
|
||||
*/
|
||||
private static final BooleanGuacamoleProperty REQUIRE_SYMBOL =
|
||||
new BooleanGuacamoleProperty() {
|
||||
|
||||
@Override
|
||||
public String getName() { return "postgresql-user-password-require-symbol"; }
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* The property which specifies whether users are prohibited from including
|
||||
* their own username in their password. By default, no such restriction is
|
||||
* imposed.
|
||||
*/
|
||||
private static final BooleanGuacamoleProperty PROHIBIT_USERNAME =
|
||||
new BooleanGuacamoleProperty() {
|
||||
|
||||
@Override
|
||||
public String getName() { return "postgresql-user-password-prohibit-username"; }
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* The Guacamole server environment.
|
||||
*/
|
||||
private final JDBCEnvironment environment;
|
||||
|
||||
/**
|
||||
* Creates a new PostgreSQLPasswordPolicy which reads the details of the
|
||||
* policy from the properties exposed by the given environment.
|
||||
*
|
||||
* @param environment
|
||||
* The environment from which password policy properties should be
|
||||
* read.
|
||||
*/
|
||||
public PostgreSQLPasswordPolicy(JDBCEnvironment environment) {
|
||||
this.environment = environment;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMinimumLength() throws GuacamoleException {
|
||||
return environment.getProperty(MIN_LENGTH, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isMultipleCaseRequired() throws GuacamoleException {
|
||||
return environment.getProperty(REQUIRE_MULTIPLE_CASE, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isNumericRequired() throws GuacamoleException {
|
||||
return environment.getProperty(REQUIRE_DIGIT, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isNonAlphanumericRequired() throws GuacamoleException {
|
||||
return environment.getProperty(REQUIRE_SYMBOL, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isUsernameProhibited() throws GuacamoleException {
|
||||
return environment.getProperty(PROHIBIT_USERNAME, false);
|
||||
}
|
||||
|
||||
}
|
@@ -21,11 +21,9 @@ package org.apache.guacamole.rest.user;
|
||||
|
||||
import com.google.inject.assistedinject.Assisted;
|
||||
import com.google.inject.assistedinject.AssistedInject;
|
||||
import java.util.UUID;
|
||||
import javax.ws.rs.Consumes;
|
||||
import javax.ws.rs.Produces;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import org.apache.guacamole.GuacamoleException;
|
||||
import org.apache.guacamole.net.auth.User;
|
||||
import org.apache.guacamole.net.auth.Directory;
|
||||
import org.apache.guacamole.net.auth.UserContext;
|
||||
@@ -69,15 +67,4 @@ public class UserDirectoryResource extends DirectoryResource<User, APIUser> {
|
||||
super(userContext, directory, translator, resourceFactory);
|
||||
}
|
||||
|
||||
@Override
|
||||
public APIUser createObject(APIUser object) throws GuacamoleException {
|
||||
|
||||
// Randomly set the password if it wasn't provided
|
||||
if (object.getPassword() == null)
|
||||
object.setPassword(UUID.randomUUID().toString());
|
||||
|
||||
return super.createObject(object);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
Reference in New Issue
Block a user