mirror of
https://github.com/gyurix1968/guacamole-client.git
synced 2025-09-06 05:07:41 +00:00
GUACAMOLE-839: Generate case-insensitive nonce values that can safely be used in domains.
This commit is contained in:
@@ -21,6 +21,7 @@ package org.apache.guacamole.auth.sso;
|
||||
|
||||
import com.google.common.io.BaseEncoding;
|
||||
import com.google.inject.Singleton;
|
||||
import java.math.BigInteger;
|
||||
import java.security.SecureRandom;
|
||||
|
||||
/**
|
||||
@@ -40,7 +41,8 @@ public class IdentifierGenerator {
|
||||
/**
|
||||
* Generates a unique and unpredictable identifier. Each identifier is at
|
||||
* least 256-bit and produced using a cryptographically-secure random
|
||||
* number generator.
|
||||
* number generator. The identifier may contain characters that differ only
|
||||
* in case.
|
||||
*
|
||||
* @return
|
||||
* A unique and unpredictable identifier with at least 256 bits of
|
||||
@@ -53,7 +55,8 @@ public class IdentifierGenerator {
|
||||
/**
|
||||
* Generates a unique and unpredictable identifier having at least the
|
||||
* given number of bits of entropy. The resulting identifier may have more
|
||||
* than the number of bits required.
|
||||
* than the number of bits required. The identifier may contain characters
|
||||
* that differ only in case.
|
||||
*
|
||||
* @param minBits
|
||||
* The number of bits of entropy that the identifier should contain.
|
||||
@@ -63,9 +66,41 @@ public class IdentifierGenerator {
|
||||
* of bits of entropy.
|
||||
*/
|
||||
public String generateIdentifier(int minBits) {
|
||||
byte[] bytes = new byte[(minBits + 23) / 24 * 3]; // Round up to nearest multiple of 3 bytes, as base64 encodes blocks of 3 bytes at a time
|
||||
secureRandom.nextBytes(bytes);
|
||||
return BaseEncoding.base64().encode(bytes);
|
||||
return generateIdentifier(minBits, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a unique and unpredictable identifier having at least the
|
||||
* given number of bits of entropy. The resulting identifier may have more
|
||||
* than the number of bits required. The identifier may contain characters
|
||||
* that differ only in case.
|
||||
*
|
||||
* @param minBits
|
||||
* The number of bits of entropy that the identifier should contain.
|
||||
*
|
||||
* @param caseSensitive
|
||||
* Whether identifiers are permitted to contain characters that vary
|
||||
* by case. If false, all characters that may vary by case will be
|
||||
* lowercase, and the generated identifier will be longer.
|
||||
*
|
||||
* @return
|
||||
* A unique and unpredictable identifier with at least the given number
|
||||
* of bits of entropy.
|
||||
*/
|
||||
public String generateIdentifier(int minBits, boolean caseSensitive) {
|
||||
|
||||
// Generate a base64 identifier if we're allowed to vary by case
|
||||
if (caseSensitive) {
|
||||
int minBytes = (minBits + 23) / 24 * 3; // Round up to nearest multiple of 3 bytes, as base64 encodes blocks of 3 bytes at a time
|
||||
byte[] bytes = new byte[minBytes];
|
||||
secureRandom.nextBytes(bytes);
|
||||
return BaseEncoding.base64().encode(bytes);
|
||||
}
|
||||
|
||||
// Generate base32 identifiers if we cannot vary by case
|
||||
minBits = (minBits + 4) / 5 * 5; // Round up to nearest multiple of 5 bits, as base32 encodes 5 bits at a time
|
||||
return new BigInteger(minBits, secureRandom).toString(32);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -22,11 +22,13 @@ package org.apache.guacamole.auth.sso;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Singleton;
|
||||
import java.util.Iterator;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
* Service for generating and validating single-use random tokens (nonces).
|
||||
* Each generated nonce is at least 128 bits and case-insensitive.
|
||||
*/
|
||||
@Singleton
|
||||
public class NonceService {
|
||||
@@ -98,7 +100,8 @@ public class NonceService {
|
||||
* valid, in milliseconds.
|
||||
*
|
||||
* @return
|
||||
* A cryptographically-secure nonce value.
|
||||
* A cryptographically-secure nonce value. Generated nonces are at
|
||||
* least 128-bit and are case-insensitive.
|
||||
*/
|
||||
public String generate(long maxAge) {
|
||||
|
||||
@@ -106,7 +109,7 @@ public class NonceService {
|
||||
sweepExpiredNonces();
|
||||
|
||||
// Generate and store nonce, along with expiration timestamp
|
||||
String nonce = idGenerator.generateIdentifier(NONCE_BITS);
|
||||
String nonce = idGenerator.generateIdentifier(NONCE_BITS, false);
|
||||
nonces.put(nonce, System.currentTimeMillis() + maxAge);
|
||||
return nonce;
|
||||
|
||||
@@ -119,7 +122,7 @@ public class NonceService {
|
||||
* invalidates that nonce.
|
||||
*
|
||||
* @param nonce
|
||||
* The nonce value to test.
|
||||
* The nonce value to test. Comparisons are case-insensitive.
|
||||
*
|
||||
* @return
|
||||
* true if the provided nonce is valid, false otherwise.
|
||||
@@ -127,7 +130,7 @@ public class NonceService {
|
||||
public boolean isValid(String nonce) {
|
||||
|
||||
// Remove nonce, verifying whether it was present at all
|
||||
Long expires = nonces.remove(nonce);
|
||||
Long expires = nonces.remove(nonce.toLowerCase(Locale.US));
|
||||
if (expires == null)
|
||||
return false;
|
||||
|
||||
|
Reference in New Issue
Block a user