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.common.io.BaseEncoding;
|
||||||
import com.google.inject.Singleton;
|
import com.google.inject.Singleton;
|
||||||
|
import java.math.BigInteger;
|
||||||
import java.security.SecureRandom;
|
import java.security.SecureRandom;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -40,7 +41,8 @@ public class IdentifierGenerator {
|
|||||||
/**
|
/**
|
||||||
* Generates a unique and unpredictable identifier. Each identifier is at
|
* Generates a unique and unpredictable identifier. Each identifier is at
|
||||||
* least 256-bit and produced using a cryptographically-secure random
|
* 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
|
* @return
|
||||||
* A unique and unpredictable identifier with at least 256 bits of
|
* 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
|
* Generates a unique and unpredictable identifier having at least the
|
||||||
* given number of bits of entropy. The resulting identifier may have more
|
* 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
|
* @param minBits
|
||||||
* The number of bits of entropy that the identifier should contain.
|
* The number of bits of entropy that the identifier should contain.
|
||||||
@@ -63,9 +66,41 @@ public class IdentifierGenerator {
|
|||||||
* of bits of entropy.
|
* of bits of entropy.
|
||||||
*/
|
*/
|
||||||
public String generateIdentifier(int minBits) {
|
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
|
return generateIdentifier(minBits, true);
|
||||||
secureRandom.nextBytes(bytes);
|
}
|
||||||
return BaseEncoding.base64().encode(bytes);
|
|
||||||
|
/**
|
||||||
|
* 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.Inject;
|
||||||
import com.google.inject.Singleton;
|
import com.google.inject.Singleton;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
|
import java.util.Locale;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Service for generating and validating single-use random tokens (nonces).
|
* Service for generating and validating single-use random tokens (nonces).
|
||||||
|
* Each generated nonce is at least 128 bits and case-insensitive.
|
||||||
*/
|
*/
|
||||||
@Singleton
|
@Singleton
|
||||||
public class NonceService {
|
public class NonceService {
|
||||||
@@ -98,7 +100,8 @@ public class NonceService {
|
|||||||
* valid, in milliseconds.
|
* valid, in milliseconds.
|
||||||
*
|
*
|
||||||
* @return
|
* @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) {
|
public String generate(long maxAge) {
|
||||||
|
|
||||||
@@ -106,7 +109,7 @@ public class NonceService {
|
|||||||
sweepExpiredNonces();
|
sweepExpiredNonces();
|
||||||
|
|
||||||
// Generate and store nonce, along with expiration timestamp
|
// 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);
|
nonces.put(nonce, System.currentTimeMillis() + maxAge);
|
||||||
return nonce;
|
return nonce;
|
||||||
|
|
||||||
@@ -119,7 +122,7 @@ public class NonceService {
|
|||||||
* invalidates that nonce.
|
* invalidates that nonce.
|
||||||
*
|
*
|
||||||
* @param nonce
|
* @param nonce
|
||||||
* The nonce value to test.
|
* The nonce value to test. Comparisons are case-insensitive.
|
||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
* true if the provided nonce is valid, false otherwise.
|
* true if the provided nonce is valid, false otherwise.
|
||||||
@@ -127,7 +130,7 @@ public class NonceService {
|
|||||||
public boolean isValid(String nonce) {
|
public boolean isValid(String nonce) {
|
||||||
|
|
||||||
// Remove nonce, verifying whether it was present at all
|
// 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)
|
if (expires == null)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user