Skip to content

Latest commit

 

History

History
560 lines (448 loc) · 26.6 KB

authorization.md

File metadata and controls

560 lines (448 loc) · 26.6 KB

Authorization in KUKSA.VAL

Background

One design goal for the authorization in KUKSA.VAL is that it should be as independent as possible from the authorization infrastructure used around it. As a result, the preferred solution has been to use a signed JWT access token where everything needed for authorization is contained within. In kuksa-val-server, this information was contained in the claim "kuksa-vss" along with the separate "admin" and "modifyTree" claims.

{
  ...
  "admin": true,
  "modifyTree": false,
  "kuksa-vss":  {
     "Vehicle.Drivetrain.Transmission.DriveType": "rw",
     "Vehicle.OBD.*": "r"
  }
}

One shortcoming in this design, was the inability to differentiate between the right to actuate signals (i.e. a form of write access) and the right to change the value of the signals (another form of write access).

Another downside was that these authorization claims where not readily compatible with the (now) widely used OAuth 2.0 Authorization Framework and JWT Profile for OAuth 2.0 Access Tokens. Using these, the same functionality is instead provided by adding a scope to the request for access tokens from the authorization server which is then included in the issued JWT access token as the "scope" claim. By aligning with these standards, KUKSA.VAL is readily compatible with a whole range of external authorization providers and libraries.

This document aims to describe how authorization in KUKSA.VAL works, and starts by providing an orientation around how it fits into the overall OAuth 2.0 Authorization Framework.

Introduction to OAuth2

Using an authorization framework like OAuth2 is well suited for an environment where third party applications need delegated access to a resource, while at the same time restricting the scope of this access to minimum.

See The OAuth 2.0 Authorization Framework for a more detailed description of the benefits, and the problems the framework aims to solve.

OAuth 2.0 defines four roles:

  • Resource owner

    An entity capable of granting access to a protected resource. When the resource owner is a person, it is referred to as an end-user.

    The resource owner in this context could be the OEM or the owner of a vehicle.

  • Resource server

    The server hosting the protected resources, capable of accepting and responding to protected resource requests using access tokens.

    The resource server in this context is KUKSA.VAL.

  • Client

    An application making protected resource requests on behalf of the resource owner and with its authorization. The term "client" does not imply any particular implementation characteristics (e.g., whether the application executes on a server, a desktop, or other devices).

    The client in this context can be apps distributed by the OEM or third parties.

  • Authorization server

    The server issuing access tokens to the client after successfully authenticating the resource owner and obtaining authorization.

    The authorization server is most likely an server controlled by the OEM and run by either the OEM or a third party (i.e. Bosch).

The resource owner can specify the scope of access rights granted to a client by including a scope in the request for an access token from the authorization server. This access token will be given to the client and is sufficient for KUKSA.VAL to independently determine if the client is allowed access to a certain resource.

Note: Strictly speaking, KUKSA.VAL also needs to verify that the subject (found in "sub") has the required access rights. See the RFC for more information. The working assumption, for now, is that anyone authorized to get a valid access token has the required access rights

In addition to the OAuth2 specification, The JWT Profile for OAuth 2.0 Access Tokens specifies a standardized structure for JWT access tokens. By following this standard, there's a greater chance for seamless integration with as many existing authorization solutions as possible.

Finally, by using access tokens for authorization, the amount of responsibility placed on KUKSA.VAL, acting as a resource server, is minimized in the overall authorization infrastructure. This should minimize the amount of bespoke code necessary to support a wide range of authorization scenarios.

JWT Access Token

JWT access tokens are supplied by adding an authorization header to the HTTP / gRPC requests.

Authorization: Bearer TOKEN

The TOKEN is a JWT access token as specified in the RFC 9068.

JWT access token:
An OAuth 2.0 access token encoded in JWT format and complying with the requirements described in this specification. [RFC 9068]

The access token contains everything the server needs to verify the authenticity of the claims contained therein.

Example of what's available in a JWT access token:

Header:

{
  "typ": "at+JWT",
  "alg": "RS256"
}

Claims:

{
    "aud": [
      "5GZCZ43D13S812715/kuksa.val",
    ],
    "iss": "https://issuer.example.com",
    "exp": 1443904177,
    "nbf": 1443904077,
    "sub": "dgaf4mvfs7",
    "client_id": "s6BhdRkqt3",
    "scope": "read:Vehicle actuate:Vehicle"
}

Data Structure

Header Description
typ REQUIRED - Media type, SHOULD be "at+jwt" for JWT access tokens.
alg The cryptographic algorithm used to secure the JWS. Resource servers conforming to RFC9068 MUST include RS256 among their supported signature algorithms.
Claim Description
iss REQUIRED - as defined in Section 4.1.1 of [RFC7519].
exp REQUIRED - as defined in Section 4.1.4 of [RFC7519].
aud REQUIRED - as defined in Section 4.1.3 of [RFC7519]. See Section 3 for indications on how an authorization server should determine the value of "aud" depending on the request.
sub REQUIRED - as defined in Section 4.1.2 of [RFC7519]. In cases of access tokens obtained through grants where a resource owner is involved, such as the authorization code grant, the value of "sub" SHOULD correspond to the subject identifier of the resource owner. In cases of access tokens obtained through grants where no resource owner is involved, such as the client credentials grant, the value of "sub" SHOULD correspond to an identifier the authorization server uses to indicate the client application. See Section 5 for more details on this scenario. Also, see Section 6 for a discussion about how different choices in assigning "sub" values can impact privacy.
client_id REQUIRED - as defined in Section 4.3 of [RFC8693].
iat REQUIRED - as defined in Section 4.1.6 of [RFC7519]. This claim identifies the time at which the JWT access token was issued.
jti REQUIRED - as defined in Section 4.1.7 of [RFC7519].

Authorization claims

If an authorization request includes a scope parameter, the corresponding issued JWT access token SHOULD include a "scope" claim as defined in Section 4.2 of [RFC8693].

All the individual scope strings in the "scope" claim MUST have meaning for the resources indicated in the "aud" claim. See Section 5 for more considerations about the relationship between scope strings and resources indicated by the "aud" claim.

Claim Description
scope The value of the scope claim is a JSON string containing a space-separated list of scopes associated with the token, in the format described in Section 3.3 of [RFC6749]

Implementation in KUKSA.VAL

A common (perhaps the most common) scenario when delegating access using OAuth2 is that the principal owner of a resource has certain access rights that needs to be verified by the resource server. This can be accomplished using the user id, group membership, roles or other entitlements present in the access token as claims.

In addition to this, the resource owner can further limit what's authorized by an access token by specifying a scope in the request to the authorization server. The issued access token will then only grant this subset of authorization to the client (e.g. a third party app) using the token.

There are currently no plans in KUKSA.VAL to separately verify the access rights of the resource owner itself, or what kind of access rights a certain group membership or role would provide. What this means in practice is that anyone authorized to get a valid access token is assumed to have full access rights within KUKSA.VAL, which will only be limited by the scope provided.

There is nothing in the design preventing KUKSA.VAL from including support for other types of verifications in the future. The scope as specified here will continue to work as a way to limit the access granted by these other means anyway.

Limit access to resources

The issued access token will typically be intended to for use with a certain resource. In the context of KUKSA.VAL, this can be a certain vehicle, or a certain backend service.

To prevent access tokens issued for one resource from being used to gain access to other, unintended resources, OAuth2 introduces the concept of Resource Indicators [RFC 8707]. By specifying the intended resource in the request to the authorization server, the resulting "aud" or audience claim should be populated with this resource.

From RFC9068:

If the request includes a "resource" parameter (as defined in [RFC8707]), the resulting JWT access token "aud" claim SHOULD have the same value as the "resource" parameter in the request.

and from RFC8707:

To prevent cross-JWT confusion, authorization servers MUST use a distinct identifier as an "aud" claim value to uniquely identify access tokens issued by the same issuer for distinct resources. For more details on cross-JWT confusion, please refer to Section 2.8 of [RFC8725].

By using a resource identifier that uniquely identifies the resource (i.e. a certain instance of KUKSA.VAL), and including this in the "aud" claim, KUKSA.VAL can verify that the access token isn't meant for another resource.

KUKSA.VAL can be configured to accept multiple "aud" claims, i.e. any one of them would be considered valid if present in an access token. It's also possible to have multiple "aud" claims in an access token, which would then be valid for multiple resources.

The uniqueness of any audience claims is a deployment decision, where the most secure option is to have unique audiences for each instance (for example based on the VIN of a vehicle). However, depending on the use case, audiences valid for a whole fleet or certain subsets/models of vehicles may be the only option."

Example of an "aud" claim:

{
  "aud": [
    "5GZCZ43D13S812715/kuksa.val",
  ],
  ...
}

where 5GZCZ43D13S812715 could be the VIN or another unique identifier available to KUKSA.VAL for local verification.

Limit access with scope

Scopes are intended to limit what is authorized by an access token. To avoid coming up with scopes of different names for every imaginable use case, KUKSA.VAL uses "prefix scopes" to allow the dynamic creation of scopes that corresponds to the intent of the authorization.

Hierarchical Access Rights

The core concept is that a scope consist of an action that represent the intent. This can be seen as the top level of an access right hierarchy that allows everything below it. To limit the scope further, sub actions and sub selections can be added to the right of this prefix. The different levels are separated by :. This provides a flexible way to limit a the scope for the intended use case.

So for example, read is the top level action in an access rights hierarchy and includes read access to everything. read:Vehicle.Speed is an example of a sub selection (a path) that limits the access rights otherwise granted by the overall read. Furthermore, this can be expanded in the future to include other sub actions such as read:field:FIELD which can also be combined with further sub selections such as the path above or things like tags etc. See possible future extensions.

Scope Description
<ACTION>[:SUB_ACTION][:<PATH>] Allow ACTION for PATH

Examples of KUKSA.VAL scope strings:

Scope string Access
read Allow client to read everything
read:Vehicle.Speed Allow client to read Vehicle.Speed (including metadata)
read:Vehicle.ADAS Allow client to read everything under Vehicle.ADAS (including metadata)
actuate:Vehicle.ADAS Allow client to actuate all actuators under Vehicle.ADAS (including read)
provide:Vehicle.Width Allow client to provide Vehicle.Width (including read)

Actions

Available actions (initially):

Action Description
read Allow client to read matching signals (and metadata)
actuate Allow client to actuate matching signals (includes read)
provide Allow client to provide matching signals (includes read)
create Allow client to create a VSS entry (under a certain path). If a VSS entry already exists, a separate scope (not fully defined yet) is needed to change it.
Subactions Description
provide:data Allow client to provide data (but not respond to actuation requests) for matching signals. (includes read)
provide:actuation Allow client to respond to actuation requests (but not provide the value) for matching signals. (includes read)

Paths

If the <PATH> is a VSS branch, the scope applies to all children of that branch.

If the <PATH> contains a wildcard (*), the wildcard only matches a single level, i.e. "Vehicle.*.IsOpen" would not match Vehicle.Body.Trunk.Rear.IsOpen, while "Vehicle.*.*.*.IsOpen" however, would.

Example 1

Allow reading and actuating all signals below Vehicle.ADAS.

{
    ...
    "scope": "read:Vehicle.ADAS actuate:Vehicle.ADAS"
}

Example 2

Allow reading & providing all entries matching "Vehicle.Body.Windshield.*.Wiping".

{
    ...
    "scope": "read:Vehicle.Body.Windshield.*.Wiping provide:Vehicle.Body.Windshield.*.Wiping"
}

Possible future extensions

Add "modify" to allow changing metadata of entries

Suggested alternative naming: edit, update

Action Description
modify Allow client to modify metadata of a VSS entry.

The reason for differentiating between creating and modifying entries is that creating an entry shouldn't have a huge effect on already running applications in the vehicle. Changing an entry on the other hand, could have a huge effect as it has the potential to invalidate the state of a lot of applications. That's why the right to create an entry doesn't automatically include the authorization to edit it.

Note: Further considerations: Runtime changes vs persistent changes.

Add "field" to scope for more granularity

Subactions for read Description
read:field:<FIELD> Allow client to only read a certain field for matching signals
Subactions for edit Description
edit:field:FIELD Allow client to edit metadata field FIELD for matching signals. (includes read)

Add "deny" scopes to limit other scopes

Scope Description
!<ACTION>:<PATH> Deny ACTION for PATH

All "deny" scopes have priority over any "allow" scope.

Examples of KUKSA.VAL scope strings:

Scope string Access
read:Vehicle Client can read everything under path Vehicle (except what is denied below)
!read:field:sensitive_field Client is not allowed to read sensitive_field
!read:Vehicle.Sensitive.Path Client is not allowed to read anything under Vehicle.Sensitive.Path

Add "tag" to scope as alternative to path

Another possible extension is to allow something other than paths to identify a (group of) signal(s).

Once scenario is that categorization information (tags) has been added to the VSS .vspec files. This information would be available as metadata for VSS entries and could be used to identify / select signals without the need to know their paths.

This isn't something that is supported today (and might never be), but it's included here to demonstrate the extensibility of the scope syntax as shown here.

Scope Description
<ACTION>:field:<FIELD>:tag:<TAG> Allow ACTION for field FIELD for signals tagged with TAG
!<ACTION>:field:<FIELD>:tag:<TAG> Deny ACTION for field FIELD for signals tagged with TAG
<ACTION>:tag:<TAG> Allow ACTION for signals tagged with TAG
!<ACTION>:tag:<TAG> Deny ACTION for signals tagged with TAG

Example:

"!read:tag:restricted !actuate:tag:restricted read:tag:low_impact actuate:tag:low_impact"

References

The OAuth 2.0 Authorization Framework

Introduction

In the traditional client-server authentication model, the client requests an access-restricted resource (protected resource) on the server by authenticating with the server using the resource owner's credentials. In order to provide third-party applications access to restricted resources, the resource owner shares its credentials with the third party. This creates several problems and limitations:

  • Third-party applications are required to store the resource owner's credentials for future use, typically a password in clear-text.

  • Servers are required to support password authentication, despite the security weaknesses inherent in passwords.

  • Third-party applications gain overly broad access to the resource owner's protected resources, leaving resource owners without any ability to restrict duration or access to a limited subset of resources.

  • Resource owners cannot revoke access to an individual third party without revoking access to all third parties, and must do so by changing the third party's password.

  • Compromise of any third-party application results in compromise of the end-user's password and all of the data protected by that password.

OAuth addresses these issues by introducing an authorization layer and separating the role of the client from that of the resource owner. In OAuth, the client requests access to resources controlled by the resource owner and hosted by the resource server, and is issued a different set of credentials than those of the resource owner.

Instead of using the resource owner's credentials to access protected resources, the client obtains an access token -- a string denoting a specific scope, lifetime, and other access attributes. Access tokens are issued to third-party clients by an authorization server with the approval of the resource owner. The client uses the access token to access the protected resources hosted by the resource server.

[RFC 6749]

Access Token

Access tokens are credentials used to access protected resources. An access token is a string representing an authorization issued to the client. The string is usually opaque to the client. Tokens represent specific scopes and durations of access, granted by the resource owner, and enforced by the resource server and authorization server.

The token may denote an identifier used to retrieve the authorization information or may self-contain the authorization information in a verifiable manner (i.e., a token string consisting of some data and a signature). Additional authentication credentials, which are beyond the scope of this specification, may be required in order for the client to use a token.

The access token provides an abstraction layer, replacing different authorization constructs (e.g., username and password) with a single token understood by the resource server. This abstraction enables issuing access tokens more restrictive than the authorization grant used to obtain them, as well as removing the resource server's need to understand a wide range of authentication methods.

[RFC 6749]

Roles

OAuth defines four roles:

  • resource owner

    An entity capable of granting access to a protected resource. When the resource owner is a person, it is referred to as an end-user.

  • resource server

    The server hosting the protected resources, capable of accepting and responding to protected resource requests using access tokens.

  • client

    An application making protected resource requests on behalf of the resource owner and with its authorization. The term "client" does not imply any particular implementation characteristics (e.g., whether the application executes on a server, a desktop, or other devices).

  • authorization server

    The server issuing access tokens to the client after successfully authenticating the resource owner and obtaining authorization.

[RFC 6749]

JSON Web Token (JWT) Profile for OAuth 2.0 Access Tokens

Introduction

This specification defines a profile for issuing OAuth 2.0 access tokens in JSON Web Token (JWT) format. Authorization servers and resource servers from different vendors can leverage this profile to issue and consume access tokens in an interoperable manner.

The original OAuth 2.0 Authorization Framework [RFC6749] specification does not mandate any specific format for access tokens. While that remains perfectly appropriate for many important scenarios, in-market use has shown that many commercial OAuth 2.0 implementations elected to issue access tokens using a format that can be parsed and validated by resource servers directly, without further authorization server involvement.

This specification aims to provide a standardized and interoperable profile as an alternative to the proprietary JWT access token layouts going forward. Besides defining a common set of mandatory and optional claims, the profile provides clear indications on how authorization request parameters determine the content of the issued JWT access token, how an authorization server can publish metadata relevant to the JWT access tokens it issues, and how a resource server should validate incoming JWT access tokens.

[RFC 9068]

Authorization Claims

If an authorization request includes a scope parameter, the corresponding issued JWT access token SHOULD include a "scope" claim as defined in Section 4.2 of [RFC8693]. All the individual scope strings in the "scope" claim MUST have meaning for the resources indicated in the "aud" claim. See Section 5 for more considerations about the relationship between scope strings and resources indicated by the "aud" claim.

[RFC 9068]

Examples of other API scope implementations

Links