WL#12376: X Protocol session connect attributes
Motivation
MySQL X Clients connection the server may differ in:
- application version,
- MySQL library version,
- OS,
- CPU,
- CPU endianess,
- programming language
While the xprotocol ensures that all data is transferred in an architecture agnostic way, the server may want know more about the client.
Having more information about clients/statistics is going to help server administrators with finding faulty clients, targeting potential issues and allow better optimizing.
User Stories
- As a DevOp I want to know the application name to route a client connection to the right cluster.
- As a DBA I want to know the client's library version to diagnose which version is causing problems with the server.
- As a ApplicationDev I want to utilize a connection pool that's shared between multiple applications in the same process to not open a new TCP connection for each new SQL session.
- As a ApplicationDev I want to send attributes that are application dependent and can be read from a stored procedure.
Goal
- allow clients to send more information about it before session establishment
Security Considerations
As session-connect-attributes are sent pre-authentication, their amount MUST be limited to reduce the attack surface.
Design Requirements
- DR1
- client MUST be able to send attributes before authentication
- DR2
- client MUST be able to send new attributes before re-authentication after session-close
- DR3
- amount of data before Authentication MUST be limited.
- DR4
- keys and values of attributes MUST NOT limited to predefined values.
- DR5
- keys MAY be duplicate.
Functional Requirements
- FR1
- session-connect-attributes MUST only apply to the next opened session.
- FR2
- session-connect-attributes MUST be able to readable from performance_schema.session_connect_attrs
- FR3
- server MUST send an error if session-connect-attributes data is too large.
- FR4
- session-reset(reset for session data, introduced by WL#12375) MUST NOT change the session-connect-attributes.
- FR5
- after session-reset(full/reauthentication), server MUST accept capabilities with session-connect-attributes.
- FR6
- after session-reset(full/reauthentication), server MUST NOT accept capabilities other than session-connect-attributes.
General
This feature is a wrapper on connection-attributes present in classic protocol. Classic client is able to send an array of key-value pairs to server, which are presented by it in "session_connect_attrs" table. Server validates the data according following constraints:
- array of key-value pairs:
- keys name must not exceed 32 characters,
- value must not exceed 1024 characters,
- cumulative size of all key-value pairs must not exceed 1MB (limited by PFS API)
- cumulative size of all key-value pairs must not exceed 64KB (limited by classic protocol)
Server doesn't put any requirements on concrete values that must be supplied in those key-value pairs. User/client library may define a template they would like to follow.
Protocol
X Protocol has already a functionality that may be used to assign some per connection data, its capability exchange in connection-negotiation-phase. X Protocol has three session-establishment phases, relation between them is visible on following state diagram:
state NegotiationOngoing
state AuthenticationOngoing
state SessionOngoing
[*] --> NegotiationOngoing
NegotiationOngoing --> NegotiationOngoing: Connection.CapabilitySet
NegotiationOngoing --> AuthenticationOngoing: Session.AuthenticationStart
AuthenticationOngoing --> SessionOngoing: Session.AuthenticationOk
SessionOngoing --> AuthenticationOngoing: Session.Reset(full-reset)
The feature requires that each 'session-connection-attributs' are assigned per session, still current design (look at previous state diagram) doesn't all setting capabilities after handling 'Session.Reset(full-reset)'.
To handle it properly, session-establishment must work according following:
state AuthenticationOngoing
state SessionOngoing
state NegotiationOngoing {
state NegotiationOnlyAttribs
state NegotiationAll
[*] --> NegotiationAll
NegotiationAll --> AuthenticationOngoing : Session.AuthenticationStart
NegotiationOnlyAttribs-->AuthenticationOngoing:Session.AuthenticationStart
}
[*] --> NegotiationOngoing
AuthenticationOngoing --> SessionOngoing: Session.AuthenticationOk
SessionOngoing -up-> NegotiationOnlyAttribs: Session.Reset(full-reset)
The difference is in transition triggered by 'Session.Reset', it moves the connection to negotiation state, still the state is divided at two sub-states:
- handle setting all capabilities,
- handle only connection-session-attributes,
we move to the second sub-state. Doing so we do not allow user to change TLS settings or other future capabilities that are specific for communication channel.
In case when client is going to reset-session-data, then session-connect-attributes are preserved because no new session is established.
There are no changes to protocol (proto files). 'CapabilitySet' defines value as 'Any' type, which means that implementation must only validate the capability name and its value under following message:
message Capability {
required string name = 1;
required Mysqlx.Datatypes.Any value = 2;
}
X Plugin must allow following capability which is going to set the 'connection-session-attributes':
- name: session_connect_attrs
value: X Protocol object (list of key-value pairs)
- keys MUST be strings
- values MUST be strings
Like:
client->server: Connection::CapabilitySet({name=session_connect_attrs, value={fld{key:"k1", value:"v1"}, fld{key:"k2", value:"v2"}...}}
client<-server: Ok
Errors
Failure in setting X Protocol capabilities, is communicated to user by error message with identifier: ER_X_CAPABILITIES_PREPARE_FAILED. Still there are a lot of different reasons why the setting connection-session-attributes may fail. Mostly those errors are consequence of key-value limitation inside the server (general-section). Thus user must be able to identify the failing cause, thus X Plugin must return unique error ID for each of those cases:
- Connection-session-attribute contains string value that length exceeds 1024 character limit
Property | Value |
---|---|
Name | ER_X_BAD_CONNECTION_SESSION_ATTRIBUTE_VALUE_LENGTH |
Error code | 5004 |
Error text | Value is too long for '%s' attribute, currently limited to |
%i |
- Connection-session-attribute contains string key that length exceeds 32 character limit
Property | Value |
---|---|
Name | ER_X_BAD_CONNECTION_SESSION_ATTRIBUTE_KEY_LENGTH |
Error code | 5005 |
Error text | Key name beginning with '%s0-32'... is too log, currently |
limited to %i |
- Connection-session-attribute contains an empty string key
Property | Value |
---|---|
Name | ER_X_BAD_CONNECTION_SESSION_ATTRIBUTE_EMPTY_KEY |
Error code | 5006 |
Error text | Empty key name given |
- X Plugin must check the capability length after decoding and if the size exceeds 64k bytes then following error must be returned:
Property | Value |
---|---|
Name | ER_X_BAD_CONNECTION_SESSION_ATTRIBUTE_LENGTH |
Error code | 5007 |
Error text | There are too many bytes in connection-session-attributes |
the capability is limited to %i |
PFS API limits the length of 'session-connection-attributes' to 1MB, thus it affect X Plugin anyway the decision was to limit it on X Protocol layer to 64 KB.
There must be an generic mechanism limiting number of bytes received by X Plugin before client successful authentication, which should be not confused with this limit.
- Connection-session-attribute contains an entry which value or key is not a string:
Property | Value |
---|---|
Name | ER_X_BAD_CONNECTION_SESSION_ATTRIBUTE_TYPE |
Error code | 5008 |
Error text | Key and values support only string values |
* After session reset user can change only one capability, which is 'session_connect_attr':
Property | Value |
---|---|
Name | ER_X_CAPABILITY_SET_NOT_ALLOWED |
Error code | 5009 |
Error text | Only session_connect_attr capability is allowed after |
Session.Reset |
* User specified same capability twice in single CapabilitySet message:
Property | Value |
---|---|
Name | ER_X_DUPLICATED_CAPABILITIES |
Error code | 5010 |
Error text | Duplicated capability: '%s' |
Neither of those errors is fatal, this means that user can retry setting those attributes:
client->server: Mysqlx.Connection.CapabilitySet(session_connect_attrs...)
client<-server: Mysqlx.Error(ER_X_BAD_CONNECTION_SESSION_ATTRIBUTE_...)
client->server: Mysqlx.Connection.CapabilitySet(session_connect_attrs...)
client<-server: Mysqlx.Error(ER_X_BAD_CONNECTION_SESSION_ATTRIBUTE_...)
Performance schema
Client needs to take into consideration that except the limitations on X Protocol there are limitations on performance schema. MySQL Server is going to truncate attributes when cumulative length per thread is longer than value defined under 'performance_schema_session_connect_attrs_size' system variable.
Examples
Mysqlx.Connection.CapabilitiesSet {
capabilities {
capabilities {
name: "session_connect_attrs"
value {
type: OBJECT
object {
fld {
key: "_OS"
value {
type: SCALAR
scalar {
type: V_STRING
v_string { value: "LINUX" }
}
}
}
}
}
}
}
}