Skip to content

Commit

Permalink
feat!: remove deprecated values (#233)
Browse files Browse the repository at this point in the history
This removes all deprecated fields and functions from the library.

BREAKING CHANGE: the following fields and backwards compatible elements have been removed; Icon field from the CredentialEntity struct, WebAuthnIcon function from the User interface, RPIcon/RPOrigin/Timeout fields from the Config struct, Transports field from the CredentialCreationResponse (new field has existed in the AuthenticatorAttestationResponse struct for quite some time which matches the spec).
Closes #221
  • Loading branch information
james-d-elliott authored Apr 27, 2024
1 parent 482cf89 commit f63fbc1
Show file tree
Hide file tree
Showing 7 changed files with 12 additions and 189 deletions.
3 changes: 3 additions & 0 deletions protocol/assertion.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,15 @@ import (
// credential for login/assertion.
type CredentialAssertionResponse struct {
PublicKeyCredential

AssertionResponse AuthenticatorAssertionResponse `json:"response"`
}

// The ParsedCredentialAssertionData is the parsed CredentialAssertionResponse that has been marshalled into a format
// that allows us to verify the client and authenticator data inside the response.
type ParsedCredentialAssertionData struct {
ParsedPublicKeyCredential

Response ParsedAssertionResponse
Raw CredentialAssertionResponse
}
Expand All @@ -30,6 +32,7 @@ type ParsedCredentialAssertionData struct {
// ParsedAssertionResponse.
type AuthenticatorAssertionResponse struct {
AuthenticatorResponse

AuthenticatorData URLEncodedBase64 `json:"authenticatorData"`
Signature URLEncodedBase64 `json:"signature"`
UserHandle URLEncodedBase64 `json:"userHandle,omitempty"`
Expand Down
10 changes: 8 additions & 2 deletions protocol/attestation.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,14 @@ type AuthenticatorAttestationResponse struct {
// The byte slice of clientDataJSON, which becomes CollectedClientData
AuthenticatorResponse

Transports []string `json:"transports,omitempty"`

AuthenticatorData URLEncodedBase64 `json:"authenticatorData"`

PublicKey URLEncodedBase64 `json:"publicKey"`

PublicKeyAlgorithm int64 `json:"publicKeyAlgorithm"`

// AttestationObject is the byte slice version of attestationObject.
// This attribute contains an attestation object, which is opaque to, and
// cryptographically protected against tampering by, the client. The
Expand All @@ -33,8 +41,6 @@ type AuthenticatorAttestationResponse struct {
// requires to validate the attestation statement, as well as to decode and
// validate the authenticator data along with the JSON-serialized client data.
AttestationObject URLEncodedBase64 `json:"attestationObject"`

Transports []string `json:"transports,omitempty"`
}

// ParsedAttestationResponse is the parsed version of AuthenticatorAttestationResponse.
Expand Down
13 changes: 0 additions & 13 deletions protocol/credential.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,12 +49,6 @@ type CredentialCreationResponse struct {
PublicKeyCredential

AttestationResponse AuthenticatorAttestationResponse `json:"response"`

// Deprecated: Transports is deprecated due to upstream changes to the API.
// Use the Transports field of AuthenticatorAttestationResponse
// instead. Transports is kept for backward compatibility, and should not
// be used by new clients.
Transports []string `json:"transports,omitempty"`
}

type ParsedCredentialCreationData struct {
Expand Down Expand Up @@ -116,13 +110,6 @@ func (ccr CredentialCreationResponse) Parse() (pcc *ParsedCredentialCreationData
return nil, ErrParsingData.WithDetails("Error parsing attestation response")
}

// TODO: Remove this as it's a backwards compatibility layer.
if len(response.Transports) == 0 && len(ccr.Transports) != 0 {
for _, t := range ccr.Transports {
response.Transports = append(response.Transports, AuthenticatorTransport(t))
}
}

var attachment AuthenticatorAttachment

switch ccr.AuthenticatorAttachment {
Expand Down
124 changes: 0 additions & 124 deletions protocol/credential_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,130 +94,6 @@ func TestParseCredentialCreationResponse(t *testing.T) {
},
errString: "",
},
{
name: "ShouldParseCredentialRequestDeprecatedTransports",
args: args{
responseName: "successDeprecatedTransports",
},
expected: &ParsedCredentialCreationData{
ParsedPublicKeyCredential: ParsedPublicKeyCredential{
ParsedCredential: ParsedCredential{
ID: "6xrtBhJQW6QU4tOaB4rrHaS2Ks0yDDL_q8jDC16DEjZ-VLVf4kCRkvl2xp2D71sTPYns-exsHQHTy3G-zJRK8g",
Type: "public-key",
},
RawID: byteID,
ClientExtensionResults: AuthenticationExtensionsClientOutputs{
"appid": true,
},
},
Response: ParsedAttestationResponse{
CollectedClientData: CollectedClientData{
Type: CeremonyType("webauthn.create"),
Challenge: "W8GzFU8pGjhoRbWrLDlamAfq_y4S1CZG1VuoeRLARrE",
Origin: "https://webauthn.io",
},
AttestationObject: AttestationObject{
Format: "none",
RawAuthData: byteAuthData,
AuthData: AuthenticatorData{
RPIDHash: byteRPIDHash,
Counter: 0,
Flags: 0x041,
AttData: AttestedCredentialData{
AAGUID: make([]byte, 16),
CredentialID: byteID,
CredentialPublicKey: byteCredentialPubKey,
},
},
},
Transports: []AuthenticatorTransport{USB, NFC, "fake"},
},
Raw: CredentialCreationResponse{
PublicKeyCredential: PublicKeyCredential{
Credential: Credential{
Type: "public-key",
ID: "6xrtBhJQW6QU4tOaB4rrHaS2Ks0yDDL_q8jDC16DEjZ-VLVf4kCRkvl2xp2D71sTPYns-exsHQHTy3G-zJRK8g",
},
RawID: byteID,
ClientExtensionResults: AuthenticationExtensionsClientOutputs{
"appid": true,
},
AuthenticatorAttachment: "not-valid",
},
AttestationResponse: AuthenticatorAttestationResponse{
AuthenticatorResponse: AuthenticatorResponse{
ClientDataJSON: byteClientDataJSON,
},
AttestationObject: byteAttObject,
},
Transports: []string{"usb", "nfc", "fake"},
},
},
errString: "",
},
{
name: "ShouldParseCredentialRequestDeprecatedTransportsShouldNotOverride",
args: args{
responseName: "successDeprecatedTransportsAndNew",
},
expected: &ParsedCredentialCreationData{
ParsedPublicKeyCredential: ParsedPublicKeyCredential{
ParsedCredential: ParsedCredential{
ID: "6xrtBhJQW6QU4tOaB4rrHaS2Ks0yDDL_q8jDC16DEjZ-VLVf4kCRkvl2xp2D71sTPYns-exsHQHTy3G-zJRK8g",
Type: "public-key",
},
RawID: byteID,
ClientExtensionResults: AuthenticationExtensionsClientOutputs{
"appid": true,
},
AuthenticatorAttachment: CrossPlatform,
},
Response: ParsedAttestationResponse{
CollectedClientData: CollectedClientData{
Type: CeremonyType("webauthn.create"),
Challenge: "W8GzFU8pGjhoRbWrLDlamAfq_y4S1CZG1VuoeRLARrE",
Origin: "https://webauthn.io",
},
AttestationObject: AttestationObject{
Format: "none",
RawAuthData: byteAuthData,
AuthData: AuthenticatorData{
RPIDHash: byteRPIDHash,
Counter: 0,
Flags: 0x041,
AttData: AttestedCredentialData{
AAGUID: make([]byte, 16),
CredentialID: byteID,
CredentialPublicKey: byteCredentialPubKey,
},
},
},
Transports: []AuthenticatorTransport{USB, NFC},
},
Raw: CredentialCreationResponse{
PublicKeyCredential: PublicKeyCredential{
Credential: Credential{
Type: "public-key",
ID: "6xrtBhJQW6QU4tOaB4rrHaS2Ks0yDDL_q8jDC16DEjZ-VLVf4kCRkvl2xp2D71sTPYns-exsHQHTy3G-zJRK8g",
},
RawID: byteID,
ClientExtensionResults: AuthenticationExtensionsClientOutputs{
"appid": true,
},
AuthenticatorAttachment: "cross-platform",
},
AttestationResponse: AuthenticatorAttestationResponse{
AuthenticatorResponse: AuthenticatorResponse{
ClientDataJSON: byteClientDataJSON,
},
AttestationObject: byteAttObject,
Transports: []string{"usb", "nfc"},
},
Transports: []string{"usb", "nfc", "fake"},
},
},
errString: "",
},
{
name: "ShouldHandleTrailingData",
args: args{
Expand Down
11 changes: 1 addition & 10 deletions protocol/entities.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,6 @@ type CredentialEntity struct {
// intended only for display, i.e., aiding the user in determining the difference between user accounts with similar
// displayNames. For example, "alexm", "alex.p.mueller@example.com" or "+14255551234".
Name string `json:"name"`

// A serialized URL which resolves to an image associated with the entity. For example,
// this could be a user’s avatar or a Relying Party's logo. This URL MUST be an a priori
// authenticated URL. Authenticators MUST accept and store a 128-byte minimum length for
// an icon member’s value. Authenticators MAY ignore an icon member’s value if its length
// is greater than 128 bytes. The URL’s scheme MAY be "data" to avoid fetches of the URL,
// at the cost of needing more storage.
//
// Deprecated: this has been removed from the specification recommendations.
Icon string `json:"icon,omitempty"`
}

// The RelyingPartyEntity represents the PublicKeyCredentialRpEntity IDL and is used to supply additional Relying Party
Expand All @@ -32,6 +22,7 @@ type CredentialEntity struct {
// Specification: §5.4.2. Relying Party Parameters for Credential Generation (https://www.w3.org/TR/webauthn/#dictionary-rp-credential-params)
type RelyingPartyEntity struct {
CredentialEntity

// A unique identifier for the Relying Party entity, which sets the RP ID.
ID string `json:"id"`
}
Expand Down
2 changes: 0 additions & 2 deletions webauthn/registration.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,15 +42,13 @@ func (webauthn *WebAuthn) BeginRegistration(user User, opts ...RegistrationOptio
DisplayName: user.WebAuthnDisplayName(),
CredentialEntity: protocol.CredentialEntity{
Name: user.WebAuthnName(),
Icon: user.WebAuthnIcon(),
},
}

entityRelyingParty := protocol.RelyingPartyEntity{
ID: webauthn.Config.RPID,
CredentialEntity: protocol.CredentialEntity{
Name: webauthn.Config.RPDisplayName,
Icon: webauthn.Config.RPIcon,
},
}

Expand Down
38 changes: 0 additions & 38 deletions webauthn/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,21 +63,6 @@ type Config struct {
Timeouts TimeoutsConfig

validated bool

// RPIcon sets the icon URL for the Relying Party Server.
//
// Deprecated: this option has been removed from newer specifications due to security considerations.
RPIcon string

// RPOrigin configures the permitted Relying Party Server Origin.
//
// Deprecated: Use RPOrigins instead.
RPOrigin string

// Timeout configures the default timeout in milliseconds.
//
// Deprecated: Use Timeouts instead.
Timeout int
}

// TimeoutsConfig represents the WebAuthn timeouts configuration.
Expand Down Expand Up @@ -120,20 +105,9 @@ func (config *Config) validate() error {
return fmt.Errorf(errFmtFieldNotValidURI, "RPID", err)
}

if config.RPIcon != "" {
if _, err = url.Parse(config.RPIcon); err != nil {
return fmt.Errorf(errFmtFieldNotValidURI, "RPIcon", err)
}
}

defaultTimeoutConfig := defaultTimeout
defaultTimeoutUVDConfig := defaultTimeoutUVD

if config.Timeout != 0 {
defaultTimeoutConfig = time.Millisecond * time.Duration(config.Timeout)
defaultTimeoutUVDConfig = defaultTimeoutConfig
}

if config.Timeouts.Login.Timeout.Milliseconds() == 0 {
config.Timeouts.Login.Timeout = defaultTimeoutConfig
}
Expand All @@ -150,14 +124,6 @@ func (config *Config) validate() error {
config.Timeouts.Registration.TimeoutUVD = defaultTimeoutUVDConfig
}

if len(config.RPOrigin) > 0 {
if len(config.RPOrigins) != 0 {
return fmt.Errorf("deprecated field 'RPOrigin' can't be defined at the same tme as the replacement field 'RPOrigins'")
}

config.RPOrigins = []string{config.RPOrigin}
}

if len(config.RPOrigins) == 0 {
return fmt.Errorf("must provide at least one value to the 'RPOrigins' field")
}
Expand Down Expand Up @@ -214,10 +180,6 @@ type User interface {

// WebAuthnCredentials provides the list of Credential objects owned by the user.
WebAuthnCredentials() []Credential

// WebAuthnIcon is a deprecated option.
// Deprecated: this has been removed from the specification recommendation. Suggest a blank string.
WebAuthnIcon() string
}

// SessionData is the data that should be stored by the Relying Party for the duration of the web authentication
Expand Down

0 comments on commit f63fbc1

Please sign in to comment.