mirror of
				https://github.com/gyurix1968/guacamole-client.git
				synced 2025-10-31 17:13:21 +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; | ||||
|  | ||||
| import org.apache.guacamole.auth.totp.user.UserVerificationService; | ||||
| import com.google.inject.Guice; | ||||
| import com.google.inject.Injector; | ||||
| 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.AuthenticationProvider; | ||||
| 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 | ||||
|         // continue | ||||
|         return context; | ||||
|         return new TOTPUserContext(context); | ||||
|  | ||||
|     } | ||||
|  | ||||
| @@ -112,7 +114,7 @@ public class TOTPAuthenticationProvider implements AuthenticationProvider { | ||||
|     public UserContext redecorate(UserContext decorated, UserContext context, | ||||
|             AuthenticatedUser authenticatedUser, Credentials credentials) | ||||
|             throws GuacamoleException { | ||||
|         return context; | ||||
|         return new TOTPUserContext(context); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|   | ||||
| @@ -19,6 +19,7 @@ | ||||
|  | ||||
| package org.apache.guacamole.auth.totp; | ||||
|  | ||||
| import org.apache.guacamole.auth.totp.user.UserVerificationService; | ||||
| import com.google.inject.AbstractModule; | ||||
| import org.apache.guacamole.GuacamoleException; | ||||
| import org.apache.guacamole.auth.totp.conf.ConfigurationService; | ||||
|   | ||||
| @@ -32,7 +32,7 @@ import java.net.URI; | ||||
| import javax.ws.rs.core.UriBuilder; | ||||
| import javax.xml.bind.DatatypeConverter; | ||||
| 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.form.Field; | ||||
| 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. | ||||
|  */ | ||||
| 
 | ||||
| package org.apache.guacamole.auth.totp; | ||||
| package org.apache.guacamole.auth.totp.user; | ||||
| 
 | ||||
| import java.security.SecureRandom; | ||||
| import java.util.Random; | ||||
| @@ -17,7 +17,7 @@ | ||||
|  * 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.inject.Inject; | ||||
| @@ -53,17 +53,6 @@ public class UserVerificationService { | ||||
|      */ | ||||
|     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. | ||||
|      */ | ||||
| @@ -111,7 +100,7 @@ public class UserVerificationService { | ||||
|         Map<String, String> attributes = context.self().getAttributes(); | ||||
| 
 | ||||
|         // 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) { | ||||
| 
 | ||||
|             // Generate random key for user | ||||
| @@ -140,7 +129,7 @@ public class UserVerificationService { | ||||
|         } | ||||
| 
 | ||||
|         // 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); | ||||
| 
 | ||||
|     } | ||||
| @@ -173,14 +162,14 @@ public class UserVerificationService { | ||||
|         Map<String, String> attributes = new HashMap<String, String>(); | ||||
| 
 | ||||
|         // Set/overwrite current TOTP key state | ||||
|         attributes.put(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_SECRET_ATTRIBUTE_NAME, BASE32.encode(key.getSecret())); | ||||
|         attributes.put(TOTPUser.TOTP_KEY_CONFIRMED_ATTRIBUTE_NAME, key.isConfirmed() ? "true" : "false"); | ||||
|         self.setAttributes(attributes); | ||||
| 
 | ||||
|         // Confirm that attributes have actually been set | ||||
|         Map<String, String> setAttributes = self.getAttributes(); | ||||
|         if (!setAttributes.containsKey(TOTP_KEY_SECRET_ATTRIBUTE_NAME) | ||||
|                 || !setAttributes.containsKey(TOTP_KEY_CONFIRMED_ATTRIBUTE_NAME)) | ||||
|         if (!setAttributes.containsKey(TOTPUser.TOTP_KEY_SECRET_ATTRIBUTE_NAME) | ||||
|                 || !setAttributes.containsKey(TOTPUser.TOTP_KEY_CONFIRMED_ATTRIBUTE_NAME)) | ||||
|             return false; | ||||
| 
 | ||||
|         // Update user object | ||||
		Reference in New Issue
	
	Block a user