use of org.wildfly.common.iteration.ByteIterator in project wildfly-elytron by wildfly-security.
the class OAuth2Server method parseInitialClientMessage.
public OAuth2InitialClientMessage parseInitialClientMessage(byte[] fromBytes) throws AuthenticationMechanismException {
byte[] messageBytes = fromBytes.clone();
ByteIterator byteIterator = ByteIterator.ofBytes(fromBytes.clone());
try {
final char cbindFlag = (char) byteIterator.next();
if (cbindFlag != 'n') {
throw log.mechChannelBindingNotSupported();
}
String authorizationID = null;
if (byteIterator.next() == ',') {
final int c = byteIterator.next();
if (c == 'a') {
if (byteIterator.next() != '=') {
throw log.mechInvalidClientMessage();
}
authorizationID = byteIterator.delimitedBy(',').asUtf8String().drainToString();
if (byteIterator.next() != ',') {
throw ElytronMessages.log.mechInvalidClientMessage();
}
}
}
String auth = getValue("auth", byteIterator.asUtf8String().drainToString());
if (auth == null) {
throw log.mechInvalidClientMessage();
}
return new OAuth2InitialClientMessage(authorizationID, auth, messageBytes);
} catch (NoSuchElementException ignored) {
throw ElytronMessages.log.mechInvalidMessageReceived();
}
}
use of org.wildfly.common.iteration.ByteIterator in project wildfly-elytron by wildfly-security.
the class ScramClient method parseInitialServerMessage.
public ScramInitialServerMessage parseInitialServerMessage(final ScramInitialClientMessage initialResponse, final byte[] bytes) throws AuthenticationMechanismException {
final byte[] challenge = bytes.clone();
final ByteIterator bi = ByteIterator.ofBytes(challenge);
final byte[] serverNonce;
final byte[] salt;
final int iterationCount;
try {
if (bi.peekNext() == 'e') {
bi.next();
if (bi.next() == '=') {
throw saslScram.scramServerRejectedAuthentication(ScramServerErrorCode.fromErrorString(bi.delimitedBy(',').asUtf8String().drainToString()));
}
throw saslScram.mechInvalidMessageReceived();
}
if (bi.next() != 'r' || bi.next() != '=') {
throw saslScram.mechInvalidMessageReceived();
}
final byte[] clientNonce = initialResponse.getRawNonce();
if (!bi.limitedTo(clientNonce.length).contentEquals(ByteIterator.ofBytes(clientNonce))) {
throw saslScram.mechNoncesDoNotMatch();
}
serverNonce = bi.delimitedBy(',').drain();
// it's a ,
bi.next();
if (bi.next() != 's' || bi.next() != '=') {
throw saslScram.mechInvalidMessageReceived();
}
salt = bi.delimitedBy(',').asUtf8String().base64Decode().drain();
// it's a ,
bi.next();
if (bi.next() != 'i' || bi.next() != '=') {
throw saslScram.mechInvalidMessageReceived();
}
iterationCount = ScramUtil.parsePosInt(bi);
if (iterationCount < minimumIterationCount) {
throw saslScram.mechIterationCountIsTooLow(iterationCount, minimumIterationCount);
}
if (iterationCount > maximumIterationCount) {
throw saslScram.mechIterationCountIsTooHigh(iterationCount, maximumIterationCount);
}
} catch (NoSuchElementException | DecodeException | NumberFormatException ex) {
throw saslScram.mechInvalidMessageReceived();
}
return new ScramInitialServerMessage(initialResponse, serverNonce, salt, iterationCount, challenge);
}
use of org.wildfly.common.iteration.ByteIterator in project wildfly-elytron by wildfly-security.
the class ScramServer method parseInitialClientMessage.
/**
* Construct an initial response object from a byte array.
*
* @param bindingCallback the optional channel binding callback result (may be {@code null})
* @param bytes the message bytes (must not be {@code null})
* @return the constructed initial response (not {@code null})
* @throws AuthenticationMechanismException if the content of the message is invalid
*/
public ScramInitialClientMessage parseInitialClientMessage(ChannelBindingCallback bindingCallback, byte[] bytes) throws AuthenticationMechanismException {
byte[] response = bytes.clone();
ByteIterator bi = ByteIterator.ofBytes(response);
try {
final char cbindFlag = (char) bi.next();
final boolean binding;
final String bindingType;
final byte[] bindingData;
if (bindingCallback != null) {
bindingType = bindingCallback.getBindingType();
bindingData = bindingCallback.getBindingData();
} else {
bindingType = null;
bindingData = null;
}
if (cbindFlag == 'p') {
if (!mechanism.isPlus()) {
throw new ScramServerException(saslScram.mechChannelBindingNotSupported(), ScramServerErrorCode.SERVER_DOES_NOT_SUPPORT_CHANNEL_BINDING);
}
if (bindingType == null || bindingData == null) {
throw new ScramServerException(saslScram.mechChannelBindingNotProvided(), ScramServerErrorCode.CHANNEL_BINDING_NOT_PROVIDED);
}
if (bi.next() != '=') {
throw saslScram.mechInvalidMessageReceived();
}
if (!bindingType.equals(bi.delimitedBy(',').asUtf8String().drainToString())) {
throw new ScramServerException(saslScram.mechChannelBindingTypeMismatch(), ScramServerErrorCode.UNSUPPORTED_CHANNEL_BINDING_TYPE);
}
binding = true;
} else if (cbindFlag == 'y') {
if (mechanism.isPlus()) {
throw new ScramServerException(saslScram.mechChannelBindingNotProvided(), ScramServerErrorCode.SERVER_DOES_SUPPORT_CHANNEL_BINDING);
}
if (bindingType != null || bindingData != null) {
throw new ScramServerException(saslScram.mechChannelBindingNotProvided(), ScramServerErrorCode.SERVER_DOES_SUPPORT_CHANNEL_BINDING);
}
binding = true;
} else if (cbindFlag == 'n') {
if (mechanism.isPlus()) {
throw new ScramServerException(saslScram.mechChannelBindingNotProvided(), ScramServerErrorCode.SERVER_DOES_SUPPORT_CHANNEL_BINDING);
}
if (bindingType != null || bindingData != null) {
throw new ScramServerException(saslScram.mechChannelBindingNotProvided(), ScramServerErrorCode.SERVER_DOES_SUPPORT_CHANNEL_BINDING);
}
binding = false;
} else {
throw saslScram.mechInvalidMessageReceived();
}
if (bi.next() != ',') {
throw saslScram.mechInvalidMessageReceived();
}
// authorization ID
final int c = bi.next();
final String authorizationID;
if (c == 'a') {
if (bi.next() != '=') {
throw saslScram.mechInvalidClientMessage();
}
authorizationID = bi.delimitedBy(',').asUtf8String().drainToString();
// skip delimiter
bi.next();
} else if (c == ',') {
authorizationID = null;
} else {
throw saslScram.mechInvalidClientMessage();
}
final int initialPartIndex = (int) bi.getIndex();
// user name
final String authenticationName;
if (bi.next() == 'n') {
if (bi.next() != '=') {
throw saslScram.mechInvalidClientMessage();
}
ByteStringBuilder bsb = new ByteStringBuilder();
StringPrep.encode(bi.delimitedBy(',').asUtf8String().drainToString(), bsb, StringPrep.PROFILE_SASL_QUERY | StringPrep.UNMAP_SCRAM_LOGIN_CHARS);
authenticationName = new String(bsb.toArray(), StandardCharsets.UTF_8);
// skip delimiter
bi.next();
} else {
throw saslScram.mechInvalidClientMessage();
}
// random nonce
if (bi.next() != 'r' || bi.next() != '=') {
throw saslScram.mechInvalidClientMessage();
}
final byte[] nonce = bi.delimitedBy(',').drain();
if (bi.hasNext()) {
throw saslScram.mechInvalidClientMessage();
}
return new ScramInitialClientMessage(mechanism, authorizationID, authenticationName, binding, bindingType, bindingData, nonce, initialPartIndex, response);
} catch (NoSuchElementException ignored) {
throw saslScram.mechInvalidMessageReceived();
}
}
use of org.wildfly.common.iteration.ByteIterator in project wildfly-elytron by wildfly-security.
the class NonceManager method useNonce.
/**
* Attempt to use the supplied nonce.
*
* A nonce might not be usable for a couple of different reasons: -
*
* <ul>
* <li>It was created too far in the past.
* <li>Validation of the signature fails.
* <li>The nonce has been used previously and re-use is disabled.
* </ul>
*
* @param nonce the nonce supplied by the client.
* @param salt additional data to use when creating the overall signature for the nonce.
* @return {@code true} if the nonce can be used, {@code false} otherwise.
* @throws AuthenticationMechanismException
*/
boolean useNonce(final String nonce, byte[] salt, int nonceCount) throws AuthenticationMechanismException {
try {
MessageDigest messageDigest = MessageDigest.getInstance(algorithm);
ByteIterator byteIterator = CodePointIterator.ofChars(nonce.toCharArray()).base64Decode();
byte[] nonceBytes = byteIterator.drain();
if (nonceBytes.length != PREFIX_LENGTH + messageDigest.getDigestLength()) {
throw log.invalidNonceLength();
}
byte[] nonceBytesWithoutPrefix = Arrays.copyOfRange(nonceBytes, PREFIX_LENGTH, nonceBytes.length);
byte[] expectedNonce = digest(nonceBytes, 0, PREFIX_LENGTH, salt, messageDigest);
if (MessageDigest.isEqual(nonceBytesWithoutPrefix, expectedNonce) == false) {
if (log.isTraceEnabled()) {
String saltString = salt == null ? "null" : ByteIterator.ofBytes(salt).hexEncode().drainToString();
log.tracef("Nonce %s rejected due to failed comparison using secret key with seed %s.", nonce, saltString);
}
return false;
}
long age = System.nanoTime() - ByteBuffer.wrap(nonceBytes, Integer.BYTES, Long.BYTES).getLong();
if (nonceCount > 0) {
synchronized (usedNonces) {
NonceState nonceState = usedNonces.get(nonce);
if (nonceState != null && nonceState.highestNonceCount < 0) {
log.tracef("Nonce %s rejected due to previously being used without a nonce count", nonce);
return false;
} else if (nonceState != null) {
if (nonceCount > nonceState.highestNonceCount) {
if (nonceState.futureCleanup.cancel(true)) {
nonceState.highestNonceCount = nonceCount;
} else {
log.tracef("Nonce %s rejected as unable to cancel clean up, likely at expiration time", nonce);
return false;
}
} else {
log.tracef("Nonce %s rejected due to highest seen nonce count %d being equal to or higher than the nonce count received %d", nonce, nonceState.highestNonceCount, nonceCount);
return false;
}
} else {
if (age < 0 || age > validityPeriodNano) {
log.tracef("Nonce %s rejected due to age %d (ns) being less than 0 or greater than the validity period %d (ns)", nonce, age, validityPeriodNano);
return false;
}
nonceState = new NonceState();
nonceState.highestNonceCount = nonceCount;
usedNonces.put(nonce, nonceState);
if (log.isTraceEnabled()) {
log.tracef("Currently %d nonces being tracked", usedNonces.size());
}
}
nonceState.futureCleanup = executor.schedule(() -> {
synchronized (usedNonces) {
usedNonces.remove(nonce);
}
}, nonceSessionTime, TimeUnit.MILLISECONDS);
}
} else {
if (age < 0 || age > validityPeriodNano) {
log.tracef("Nonce %s rejected due to age %d (ns) being less than 0 or greater than the validity period %d (ns)", nonce, age, validityPeriodNano);
return false;
}
if (singleUse) {
synchronized (usedNonces) {
NonceState nonceState = usedNonces.get(nonce);
if (nonceState != null) {
log.tracef("Nonce %s rejected due to previously being used", nonce);
return false;
} else {
nonceState = new NonceState();
usedNonces.put(nonce, nonceState);
if (log.isTraceEnabled()) {
log.tracef("Currently %d nonces being tracked", usedNonces.size());
}
executor.schedule(() -> {
synchronized (usedNonces) {
usedNonces.remove(nonce);
}
}, validityPeriodNano - age, TimeUnit.NANOSECONDS);
}
}
}
}
return true;
} catch (GeneralSecurityException e) {
throw new IllegalStateException(e);
}
}
use of org.wildfly.common.iteration.ByteIterator in project wildfly-elytron by wildfly-security.
the class BasicPasswordSpecEncoding method decode.
/**
* Decode the given byte array and create a {@link PasswordSpec} from it.
*
* @param encoded the byte array representing the encoded password
* @return a {@link PasswordSpec} instance created from the encoded password or null if no decoder was capable to decode the given format.
*/
public static PasswordSpec decode(byte[] encoded) {
ByteIterator iterator = ByteIterator.ofBytes(encoded);
int identifier;
try {
identifier = iterator.next();
} catch (Exception e) {
throw ElytronMessages.log.couldNotObtainKeySpecEncodingIdentifier();
}
switch(identifier) {
case CLEAR_PASSWORD_SPEC_ID:
return decodeClearPasswordSpec(iterator);
case DIGEST_PASSWORD_SPEC_ID:
return decodeDigestPasswordSpec(iterator);
case HASH_PASSWORD_SPEC_ID:
return decodeHashPasswordSpec(iterator);
case SALTED_HASH_PASSWORD_SPEC_ID:
return decodeSaltedHashPasswordSpec(iterator);
case ITERATED_SALTED_HASH_SPEC_ID:
return decodeIteratedSaltedHashPasswordSpec(iterator);
default:
return null;
}
}
Aggregations