mirror of
https://github.com/gyurix1968/guacamole-client.git
synced 2025-09-07 05:31:22 +00:00
GUACAMOLE-96: Block external access to TOTP-internal attributes.
This commit is contained in:
@@ -19,9 +19,11 @@
|
|||||||
|
|
||||||
package org.apache.guacamole.auth.totp;
|
package org.apache.guacamole.auth.totp;
|
||||||
|
|
||||||
|
import org.apache.guacamole.auth.totp.user.UserVerificationService;
|
||||||
import com.google.inject.Guice;
|
import com.google.inject.Guice;
|
||||||
import com.google.inject.Injector;
|
import com.google.inject.Injector;
|
||||||
import org.apache.guacamole.GuacamoleException;
|
import org.apache.guacamole.GuacamoleException;
|
||||||
|
import org.apache.guacamole.auth.totp.user.TOTPUserContext;
|
||||||
import org.apache.guacamole.net.auth.AuthenticatedUser;
|
import org.apache.guacamole.net.auth.AuthenticatedUser;
|
||||||
import org.apache.guacamole.net.auth.AuthenticationProvider;
|
import org.apache.guacamole.net.auth.AuthenticationProvider;
|
||||||
import org.apache.guacamole.net.auth.Credentials;
|
import org.apache.guacamole.net.auth.Credentials;
|
||||||
@@ -104,7 +106,7 @@ public class TOTPAuthenticationProvider implements AuthenticationProvider {
|
|||||||
|
|
||||||
// User has been verified, and authentication should be allowed to
|
// User has been verified, and authentication should be allowed to
|
||||||
// continue
|
// continue
|
||||||
return context;
|
return new TOTPUserContext(context);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -112,7 +114,7 @@ public class TOTPAuthenticationProvider implements AuthenticationProvider {
|
|||||||
public UserContext redecorate(UserContext decorated, UserContext context,
|
public UserContext redecorate(UserContext decorated, UserContext context,
|
||||||
AuthenticatedUser authenticatedUser, Credentials credentials)
|
AuthenticatedUser authenticatedUser, Credentials credentials)
|
||||||
throws GuacamoleException {
|
throws GuacamoleException {
|
||||||
return context;
|
return new TOTPUserContext(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@@ -19,6 +19,7 @@
|
|||||||
|
|
||||||
package org.apache.guacamole.auth.totp;
|
package org.apache.guacamole.auth.totp;
|
||||||
|
|
||||||
|
import org.apache.guacamole.auth.totp.user.UserVerificationService;
|
||||||
import com.google.inject.AbstractModule;
|
import com.google.inject.AbstractModule;
|
||||||
import org.apache.guacamole.GuacamoleException;
|
import org.apache.guacamole.GuacamoleException;
|
||||||
import org.apache.guacamole.auth.totp.conf.ConfigurationService;
|
import org.apache.guacamole.auth.totp.conf.ConfigurationService;
|
||||||
|
@@ -32,7 +32,7 @@ import java.net.URI;
|
|||||||
import javax.ws.rs.core.UriBuilder;
|
import javax.ws.rs.core.UriBuilder;
|
||||||
import javax.xml.bind.DatatypeConverter;
|
import javax.xml.bind.DatatypeConverter;
|
||||||
import org.apache.guacamole.GuacamoleException;
|
import org.apache.guacamole.GuacamoleException;
|
||||||
import org.apache.guacamole.auth.totp.UserTOTPKey;
|
import org.apache.guacamole.auth.totp.user.UserTOTPKey;
|
||||||
import org.apache.guacamole.auth.totp.conf.ConfigurationService;
|
import org.apache.guacamole.auth.totp.conf.ConfigurationService;
|
||||||
import org.apache.guacamole.form.Field;
|
import org.apache.guacamole.form.Field;
|
||||||
import org.codehaus.jackson.annotate.JsonProperty;
|
import org.codehaus.jackson.annotate.JsonProperty;
|
||||||
|
@@ -0,0 +1,102 @@
|
|||||||
|
/*
|
||||||
|
* 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.totp.user;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import org.apache.guacamole.net.auth.DelegatingUser;
|
||||||
|
import org.apache.guacamole.net.auth.User;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TOTP-specific User implementation which wraps a User from another extension,
|
||||||
|
* hiding and blocking access to the core attributes used by TOTP.
|
||||||
|
*/
|
||||||
|
public class TOTPUser extends DelegatingUser {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The name of the user attribute which stores the TOTP key.
|
||||||
|
*/
|
||||||
|
public static final String TOTP_KEY_SECRET_ATTRIBUTE_NAME = "guac-totp-key-secret";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The name of the user attribute defines whether the TOTP key has been
|
||||||
|
* confirmed by the user, and the user is thus fully enrolled.
|
||||||
|
*/
|
||||||
|
public static final String TOTP_KEY_CONFIRMED_ATTRIBUTE_NAME = "guac-totp-key-confirmed";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The User object wrapped by this TOTPUser.
|
||||||
|
*/
|
||||||
|
private final User undecorated;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wraps the given User object, hiding and blocking access to the core
|
||||||
|
* attributes used by TOTP.
|
||||||
|
*
|
||||||
|
* @param user
|
||||||
|
* The User object to wrap.
|
||||||
|
*/
|
||||||
|
public TOTPUser(User user) {
|
||||||
|
super(user);
|
||||||
|
this.undecorated = user;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the User object wrapped by this TOTPUser.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* The wrapped User object.
|
||||||
|
*/
|
||||||
|
public User getUndecorated() {
|
||||||
|
return undecorated;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<String, String> getAttributes() {
|
||||||
|
|
||||||
|
// Create independent, mutable copy of attributes
|
||||||
|
Map<String, String> attributes =
|
||||||
|
new HashMap<String, String>(super.getAttributes());
|
||||||
|
|
||||||
|
// Do not expose any TOTP-related attributes outside this extension
|
||||||
|
attributes.remove(TOTP_KEY_SECRET_ATTRIBUTE_NAME);
|
||||||
|
attributes.remove(TOTP_KEY_CONFIRMED_ATTRIBUTE_NAME);
|
||||||
|
|
||||||
|
// Expose only non-TOTP attributes
|
||||||
|
return attributes;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setAttributes(Map<String, String> attributes) {
|
||||||
|
|
||||||
|
// Create independent, mutable copy of attributes
|
||||||
|
attributes = new HashMap<String, String>(attributes);
|
||||||
|
|
||||||
|
// Do not expose any TOTP-related attributes outside this extension
|
||||||
|
attributes.remove(TOTP_KEY_SECRET_ATTRIBUTE_NAME);
|
||||||
|
attributes.remove(TOTP_KEY_CONFIRMED_ATTRIBUTE_NAME);
|
||||||
|
|
||||||
|
// Set only non-TOTP attributes
|
||||||
|
super.setAttributes(attributes);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -0,0 +1,64 @@
|
|||||||
|
/*
|
||||||
|
* 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.totp.user;
|
||||||
|
|
||||||
|
import org.apache.guacamole.GuacamoleException;
|
||||||
|
import org.apache.guacamole.net.auth.DecoratingDirectory;
|
||||||
|
import org.apache.guacamole.net.auth.DelegatingUserContext;
|
||||||
|
import org.apache.guacamole.net.auth.Directory;
|
||||||
|
import org.apache.guacamole.net.auth.User;
|
||||||
|
import org.apache.guacamole.net.auth.UserContext;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TOTP-specific UserContext implementation which wraps the UserContext of
|
||||||
|
* some other extension, providing (or hiding) additional data.
|
||||||
|
*/
|
||||||
|
public class TOTPUserContext extends DelegatingUserContext {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new TOTPUserContext which wraps the given UserContext,
|
||||||
|
* providing (or hiding) additional TOTP-specific data.
|
||||||
|
*
|
||||||
|
* @param userContext
|
||||||
|
* The UserContext to wrap.
|
||||||
|
*/
|
||||||
|
public TOTPUserContext(UserContext userContext) {
|
||||||
|
super(userContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Directory<User> getUserDirectory() throws GuacamoleException {
|
||||||
|
return new DecoratingDirectory<User>(super.getUserDirectory()) {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected User decorate(User object) {
|
||||||
|
return new TOTPUser(object);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected User undecorate(User object) {
|
||||||
|
assert(object instanceof TOTPUser);
|
||||||
|
return ((TOTPUser) object).getUndecorated();
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -17,7 +17,7 @@
|
|||||||
* under the License.
|
* under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.apache.guacamole.auth.totp;
|
package org.apache.guacamole.auth.totp.user;
|
||||||
|
|
||||||
import java.security.SecureRandom;
|
import java.security.SecureRandom;
|
||||||
import java.util.Random;
|
import java.util.Random;
|
@@ -17,7 +17,7 @@
|
|||||||
* under the License.
|
* under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.apache.guacamole.auth.totp;
|
package org.apache.guacamole.auth.totp.user;
|
||||||
|
|
||||||
import com.google.common.io.BaseEncoding;
|
import com.google.common.io.BaseEncoding;
|
||||||
import com.google.inject.Inject;
|
import com.google.inject.Inject;
|
||||||
@@ -53,17 +53,6 @@ public class UserVerificationService {
|
|||||||
*/
|
*/
|
||||||
private final Logger logger = LoggerFactory.getLogger(UserVerificationService.class);
|
private final Logger logger = LoggerFactory.getLogger(UserVerificationService.class);
|
||||||
|
|
||||||
/**
|
|
||||||
* The name of the user attribute which stores the TOTP key.
|
|
||||||
*/
|
|
||||||
private static final String TOTP_KEY_SECRET_ATTRIBUTE_NAME = "guac-totp-key-secret";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The name of the user attribute defines whether the TOTP key has been
|
|
||||||
* confirmed by the user, and the user is thus fully enrolled.
|
|
||||||
*/
|
|
||||||
private static final String TOTP_KEY_CONFIRMED_ATTRIBUTE_NAME = "guac-totp-key-confirmed";
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* BaseEncoding instance which decoded/encodes base32.
|
* BaseEncoding instance which decoded/encodes base32.
|
||||||
*/
|
*/
|
||||||
@@ -111,7 +100,7 @@ public class UserVerificationService {
|
|||||||
Map<String, String> attributes = context.self().getAttributes();
|
Map<String, String> attributes = context.self().getAttributes();
|
||||||
|
|
||||||
// If no key is defined, attempt to generate a new key
|
// If no key is defined, attempt to generate a new key
|
||||||
String secret = attributes.get(TOTP_KEY_SECRET_ATTRIBUTE_NAME);
|
String secret = attributes.get(TOTPUser.TOTP_KEY_SECRET_ATTRIBUTE_NAME);
|
||||||
if (secret == null) {
|
if (secret == null) {
|
||||||
|
|
||||||
// Generate random key for user
|
// Generate random key for user
|
||||||
@@ -140,7 +129,7 @@ public class UserVerificationService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Otherwise, parse value from attributes
|
// Otherwise, parse value from attributes
|
||||||
boolean confirmed = "true".equals(attributes.get(TOTP_KEY_CONFIRMED_ATTRIBUTE_NAME));
|
boolean confirmed = "true".equals(attributes.get(TOTPUser.TOTP_KEY_CONFIRMED_ATTRIBUTE_NAME));
|
||||||
return new UserTOTPKey(username, key, confirmed);
|
return new UserTOTPKey(username, key, confirmed);
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -173,14 +162,14 @@ public class UserVerificationService {
|
|||||||
Map<String, String> attributes = new HashMap<String, String>();
|
Map<String, String> attributes = new HashMap<String, String>();
|
||||||
|
|
||||||
// Set/overwrite current TOTP key state
|
// Set/overwrite current TOTP key state
|
||||||
attributes.put(TOTP_KEY_SECRET_ATTRIBUTE_NAME, BASE32.encode(key.getSecret()));
|
attributes.put(TOTPUser.TOTP_KEY_SECRET_ATTRIBUTE_NAME, BASE32.encode(key.getSecret()));
|
||||||
attributes.put(TOTP_KEY_CONFIRMED_ATTRIBUTE_NAME, key.isConfirmed() ? "true" : "false");
|
attributes.put(TOTPUser.TOTP_KEY_CONFIRMED_ATTRIBUTE_NAME, key.isConfirmed() ? "true" : "false");
|
||||||
self.setAttributes(attributes);
|
self.setAttributes(attributes);
|
||||||
|
|
||||||
// Confirm that attributes have actually been set
|
// Confirm that attributes have actually been set
|
||||||
Map<String, String> setAttributes = self.getAttributes();
|
Map<String, String> setAttributes = self.getAttributes();
|
||||||
if (!setAttributes.containsKey(TOTP_KEY_SECRET_ATTRIBUTE_NAME)
|
if (!setAttributes.containsKey(TOTPUser.TOTP_KEY_SECRET_ATTRIBUTE_NAME)
|
||||||
|| !setAttributes.containsKey(TOTP_KEY_CONFIRMED_ATTRIBUTE_NAME))
|
|| !setAttributes.containsKey(TOTPUser.TOTP_KEY_CONFIRMED_ATTRIBUTE_NAME))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Update user object
|
// Update user object
|
Reference in New Issue
Block a user