Skip to content

Commit

Permalink
WL#15197, Support WebauthN in fido authentication plugin.
Browse files Browse the repository at this point in the history
Change-Id: Ia83d2c1f7619e7c0febbbc426a7cfef4d0feae43
  • Loading branch information
fjssilva committed Sep 1, 2023
1 parent 4e97a3e commit bb0f86d
Show file tree
Hide file tree
Showing 9 changed files with 436 additions and 6 deletions.
2 changes: 2 additions & 0 deletions CHANGES
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@

Version 8.2.0

- WL#15197, Support WebauthN in fido authentication plugin.

- Fix for Bug#107215 (Bug#34139593), ClassCastException: java.time.LocalDateTime cannot be cast to java.sql.Timestamp.

- WL#15747, Remove autoDeserialize feature.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
/*
* Copyright (c) 2023, Oracle and/or its affiliates.
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, version 2.0, as published by the
* Free Software Foundation.
*
* This program is also distributed with certain software (including but not
* limited to OpenSSL) that is licensed under separate terms, as designated in a
* particular file or component or in included license documentation. The
* authors of MySQL hereby grant you an additional permission to link the
* program and your derivative works with the separately licensed software that
* they have included with MySQL.
*
* Without limiting anything contained in the foregoing, this file, which is
* part of MySQL Connector/J, is also subject to the Universal FOSS Exception,
* version 1.0, a copy of which can be found at
* http://oss.oracle.com/licenses/universal-foss-exception.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License, version 2.0,
* for more details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/

package com.mysql.cj.callback;

import java.util.ArrayList;
import java.util.List;

/**
* The callback object used by the authentication plugin AuthenticationWebAuthnClient to exchange authenticator data between the driver and the client
* application.
*
* Applications must implement a MysqlCallbackHandler to manage the interaction with authenticator devices and provide the data required to proceed with
* FIDO2/WebAuthn authentication. Such handler receives an instance of this class, which must then be used to obtain the data to send to the device and to
* submit the produced authenticator data and signature into the driver.
*/
public class WebAuthnAuthenticationCallback implements MysqlCallback {

// FIDO inputs.
private byte[] clientDataHash;
private String relyingPartyId;
private byte[] credentialId;

// FIDO outputs.
private boolean supportsCredentialManagement;
private List<byte[]> authenticatorDataEntries;
private List<byte[]> signatureEntries;

/**
* Instances of this object are used to exchange FIDO data between the client application and the driver and are responsible for managing all the
* interactions with the FIDO authenticator devices.
*
* @param clientDataHash
* the client data hash
* @param relyingPartyId
* the relying party id
* @param credentialId
* the credential id
*/
public WebAuthnAuthenticationCallback(byte[] clientDataHash, String relyingPartyId, byte[] credentialId) {
this.clientDataHash = clientDataHash;
this.relyingPartyId = relyingPartyId;
this.credentialId = credentialId;
this.authenticatorDataEntries = new ArrayList<>();
this.signatureEntries = new ArrayList<>();
}

/**
* Returns the FIDO Client Data Hash (an SHA-256 hash computed from the Client Data JSON) for the upcoming authenticator interaction.
*
* @return
* the client data hash
*/
public byte[] getClientDataHash() {
return this.clientDataHash;
}

/**
* Returns the FIDO Relying Party Id for the upcoming authenticator interaction.
*
* @return
* the relying party id
*/
public String getRelyingPartyId() {
return this.relyingPartyId;
}

/**
* Returns the FIDO Credential Id for the upcoming authenticator interaction.
*
* @return
* the credential id
*/
public byte[] getCredentialId() {
return this.credentialId;
}

/**
* Sets whether this FIDO Authenticator device supports Credential Management.
*
* @param supportsCredMan
* is credential management supported?
*/
public void setSupportsCredentialManagement(boolean supportsCredMan) {
this.supportsCredentialManagement = supportsCredMan;
}

/**
* Returns whether this FIDO Authenticator device supports Credential Management.
*
* @return
* is credential management supported?
*/
public boolean getSupportsCredentialManagement() {
return this.supportsCredentialManagement;
}

/**
* Adds a FIDO Authenticator Data produced by the authenticator interaction.
*
* @param authenticatorData
* the authenticator data
*/
public void addAuthenticatorData(byte[] authenticatorData) {
this.authenticatorDataEntries.add(authenticatorData);
}

/**
* Returns one of FIDO Authenticator Data produced by the authenticator interaction.
*
* @param idx
* the index of the Authenticator Data to return
*
* @return
* the authenticator data
*/
public byte[] getAuthenticatorData(int idx) {
if (idx >= this.authenticatorDataEntries.size()) {
return null;
}
return this.authenticatorDataEntries.get(idx);
}

/**
* Adds a FIDO Signature produced by the authenticator interaction.
*
* @param signature
* the signature
*/
public void addSignature(byte[] signature) {
this.signatureEntries.add(signature);
}

/**
* Returns one of the FIDO Signatures produced by the authenticator interaction
*
* @param idx
* the index of the Signature to return
*
* @return
* the signature
*/
public byte[] getSignature(int idx) {
if (idx >= this.signatureEntries.size()) {
return null;
}
return this.signatureEntries.get(idx);
}

/**
* Returns the number of assertions produced by the authenticator interaction
*
* @return
* the number of assertions
*/
public int getAssertCount() {
return Math.min(this.authenticatorDataEntries.size(), this.signatureEntries.size());
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -209,13 +209,16 @@ public enum DatabaseTerm {
Messages.getString("ConnectionProperties.ldapServerHostname"), "8.0.23", CATEGORY_AUTH, Integer.MIN_VALUE + 9),

new StringPropertyDefinition(PropertyKey.ociConfigFile, DEFAULT_VALUE_NULL_STRING, RUNTIME_MODIFIABLE,
Messages.getString("ConnectionProperties.ociConfigFile"), "8.0.27", CATEGORY_AUTH, Integer.MIN_VALUE + 7),
Messages.getString("ConnectionProperties.ociConfigFile"), "8.0.27", CATEGORY_AUTH, Integer.MIN_VALUE + 10),

new StringPropertyDefinition(PropertyKey.ociConfigProfile, "DEFAULT", RUNTIME_MODIFIABLE,
Messages.getString("ConnectionProperties.ociConfigProfile"), "8.0.33", CATEGORY_AUTH, Integer.MIN_VALUE + 8),
Messages.getString("ConnectionProperties.ociConfigProfile"), "8.0.33", CATEGORY_AUTH, Integer.MIN_VALUE + 11),

new StringPropertyDefinition(PropertyKey.authenticationFidoCallbackHandler, DEFAULT_VALUE_NULL_STRING, RUNTIME_MODIFIABLE,
Messages.getString("ConnectionProperties.authenticationFidoCallbackHandler"), "8.0.29", CATEGORY_AUTH, Integer.MIN_VALUE + 9),
Messages.getString("ConnectionProperties.authenticationFidoCallbackHandler"), "8.0.29", CATEGORY_AUTH, Integer.MIN_VALUE + 12),

new StringPropertyDefinition(PropertyKey.authenticationWebAuthnCallbackHandler, DEFAULT_VALUE_NULL_STRING, RUNTIME_MODIFIABLE,
Messages.getString("ConnectionProperties.authenticationWebAuthnCallbackHandler"), "8.2.0", CATEGORY_AUTH, Integer.MIN_VALUE + 13),

//
// CATEGORY_CONNECTION
Expand Down
1 change: 1 addition & 0 deletions src/main/core-api/java/com/mysql/cj/conf/PropertyKey.java
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ public enum PropertyKey {
alwaysSendSetIsolation("alwaysSendSetIsolation", true), //
authenticationFidoCallbackHandler("authenticationFidoCallbackHandler", true), //
authenticationPlugins("authenticationPlugins", true), //
authenticationWebAuthnCallbackHandler("authenticationWebAuthnCallbackHandler", true), //
autoClosePStmtStreams("autoClosePStmtStreams", true), //
autoGenerateTestcaseScript("autoGenerateTestcaseScript", true), //
autoReconnect("autoReconnect", true), //
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@
import com.mysql.cj.protocol.a.authentication.AuthenticationKerberosClient;
import com.mysql.cj.protocol.a.authentication.AuthenticationLdapSaslClientPlugin;
import com.mysql.cj.protocol.a.authentication.AuthenticationOciClient;
import com.mysql.cj.protocol.a.authentication.AuthenticationWebAuthnClient;
import com.mysql.cj.protocol.a.authentication.CachingSha2PasswordPlugin;
import com.mysql.cj.protocol.a.authentication.MysqlClearPasswordPlugin;
import com.mysql.cj.protocol.a.authentication.MysqlNativePasswordPlugin;
Expand Down Expand Up @@ -260,6 +261,7 @@ private void loadAuthenticationPlugins() {
pluginsToInit.add(new AuthenticationKerberosClient());
pluginsToInit.add(new AuthenticationOciClient());
pluginsToInit.add(new AuthenticationFidoClient());
pluginsToInit.add(new AuthenticationWebAuthnClient());

// plugins from authenticationPluginClasses connection parameter
String authenticationPluginClasses = this.propertySet.getStringProperty(PropertyKey.authenticationPlugins).getValue();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ public boolean nextAuthenticationStep(NativePacketPayload fromServer, List<Nativ
throw ExceptionFactory.createException(Messages.getString("AuthenticationFidoClientPlugin.InvalidSignature"));
}

NativePacketPayload packet = new NativePacketPayload(authenticatorData.length + signature.length + 4); // 2 + 2 Bytes for length encoding.
NativePacketPayload packet = new NativePacketPayload(authenticatorData.length + signature.length + 2); // 1 + 1 Bytes for length encoding.
packet.writeBytes(StringSelfDataType.STRING_LENENC, authenticatorData);
packet.writeBytes(StringSelfDataType.STRING_LENENC, signature);
toServer.add(packet);
Expand Down
Loading

0 comments on commit bb0f86d

Please sign in to comment.