Skip to content

Commit

Permalink
Draft design for single-use-token authenticator
Browse files Browse the repository at this point in the history
  • Loading branch information
szh committed Sep 28, 2023
1 parent 7044dbc commit f8256db
Show file tree
Hide file tree
Showing 8 changed files with 566 additions and 19 deletions.
49 changes: 30 additions & 19 deletions design/authenticators/AUTHENTICATORS.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,24 +4,26 @@ Authenticators allow you to customize the user login and authentication methods
for Conjur. There are two endpoints used by Conjur to authenticate users and
services to the API.

* '/login' is used to authenticate users with a username and password. This
- '/login' is used to authenticate users with a username and password. This
endpoint allows users to initially authenticate with a memorable password
and exchange it for an API key. The format of this key is configurable by
the authenticator.

* '/authenticate' is used to authenticate either a user or service and returns
- '/authenticate' is used to authenticate either a user or service and returns
a short-lived access token for API requests.

## Existing Authenticators

Links to the current Authenticator Feature specs:
* [Authn-LDAP](authn_ldap.md)
* [Authn-IAM](authn_iam.md)
* [Authn-OIDC](authn_oidc.md)
* [Authn-Azure](authn_azure/authn_azure_solution_design.md)
* [Authn-GCP](authn_gcp/authn_gcp_solution_design.md)

- [Authn-LDAP](authn_ldap.md)
- [Authn-IAM](authn_iam.md)
- [Authn-OIDC](authn_oidc.md)
- [Authn-Azure](authn_azure/authn_azure_solution_design.md)
- [Authn-GCP](authn_gcp/authn_gcp_solution_design.md)

## Authenticator Status

This feature allows the person who configures an authenticator to get immediate feedback on
its configuration. If there was a problem during the authenticator configuration process,
the reason will be returned to the user so that they can make the necessary changes.
Expand All @@ -35,9 +37,11 @@ separate login step allows users to authenticate with a memorable password,
while using a random, rotatable access key for actual API authentication.

To login, send a `GET` request to:
```

```txt
/:authenticator-type/:optional-service-id/:conjur-account/login
```

[Basic Authentication](https://developer.mozilla.org/en-US/docs/Web/HTTP/Authentication)
is used to send the username and password.

Expand Down Expand Up @@ -68,9 +72,11 @@ Successful authentication returns a new **Conjur token**, which you can use to
make subsequent requests to protected Conjur services.

To authenticate and receive this token, `POST` to:
```

```txt
/:authenticator-type/:optional-service-id/:conjur-account/:username/authenticate
```

with the key (or other credential relevant to your authenticator) as plain
text in the request body.

Expand All @@ -80,7 +86,6 @@ The request parameters are the same as login with the addition of:
your authenticator. This could be an ordinary password, an API key, an
OAuth token, etc -- depending on the type of authenticator.


## Security requirements

### Must whitelist before using
Expand All @@ -99,7 +104,8 @@ authenticators must be explicitly whitelisted via the environment variable

Here is an example `CONJUR_AUTHENTICATORS` which whitelists an LDAP
authenticator as well as the default Conjur authenticator:
```

```txt
CONJUR_AUTHENTICATORS=authn-ldap/sysadmins,authn
```

Expand All @@ -112,22 +118,26 @@ webservices in your Conjur policy, and users must be authorized to use them.
This requires two steps:

1. Add the authenticator as a webservice in your conjur policy:
```yaml
- !policy
id: conjur/my-authenticator/optional-service-id
```

```yaml
- !policy
id: conjur/my-authenticator/optional-service-id
```
2. Add any users that need to access it to your policy, and grant them the
`authenticate` privilege.


## Creating custom authenticators:
## Creating custom authenticators

1. Create a new directory under `/app/domain/authentication`. For example:
```

```txt
/app/domain/authentication/my_authenticator
```

2. That directory must contain a file named `authenticator.rb`, with the
following structure:
following structure:

```ruby
module Authentication
module MyAuthenticator
Expand Down Expand Up @@ -182,6 +192,7 @@ end
authenticator is instantiated by conjur, it will be passed the `ENV` through
the kwarg `env`. If you don't need any configuration from the environment,
you can opt out like so:

```ruby
module Authentication
module MyAuthenticator
Expand Down
277 changes: 277 additions & 0 deletions design/authenticators/authn_sut/authn_sut_solution_design.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,277 @@
# Single Use Token (SUT) Authenticator

## Overview/Introduction

The Single Use Token (SUT) Authenticator is a new authenticator for Conjur that
will allow users to authenticate to Conjur using a single-use token. A user will
be able to generate a single use token by providing their username and password
to a new API endpoint. The user will then be able to use the token to
authenticate to Conjur.

## Summary of Existing Functionality

There is currently no way to create a single-use token for authenticating to
Conjur.

## Requirements

The driver behind this effort is to enable integration between Conjur UI and
PSM. That integration will require a mechanism for generating a single-use token
that can be used to authenticate to Conjur. The requirements for this effort are
as follows:

### Feature Spec for Conjur UI-PSM Integration (CNJR-2392)

> Privileged Session Manager (PSM) enables users to log on to remote
> machines/applications securely through a proxy machine facilitating
> streamlined and native workflows for the IT admins. Conjur is now going to
> integrate with PSM providing integrity across Cyberark products and easy
> access to the Conjur UI via PSM.
>
> In order for PSM to connect to the Conjur UI, a new API(s) would be provided
> that PSM could call to establish the UI session and login the user directly
> into the main UI dashboard, without showing the initial login screen. More
> details will be added in the solution design (TBD).
>
> The overall UX will remain the same where users will continue to use the
> existing workflow of logging onto the PVWA, clicking connect on a defined
> Conjur instance 1 and connecting through PSM straight into the Conjur UI
> console.
The SUT authenticator will be the mechanism used to authenticate the user to
Conjur when they click "Connect" on a Conjur instance in PVWA. PSM will generate
a SUT for the user using their stored username and password or API key. PSM will
then pass the SUT to the Conjur UI via a URL parameter. The Conjur UI will use
the SUT to authenticate the user to Conjur and start a session.

## Assumptions and Prerequisites

Assumptions: Defining the assumptions being made in preparing this Solution
Design. Detailing why these assumptions are valid and/or acceptable.
Prerequisites: Do we need additional tooling to develop this feature? Do we need
additional tooling to test this feature in our pipeline? What needs to be in
place to build this feature?

## Out-of-scope

- SUTs will not be able to be used to authenticate to Conjur via the CLI
- SUTs are intended to be used in automated processes. The CLI is intended to
be used by humans (developers, operators, etc.)
- There are many possible use cases for SUTs. This effort will focus on the
basic use case necessary for Conjur UI-PSM integration. Additional use cases
may be considered in the future.
- The PSM integration itself will not be part of this effort. This effort will
only focus on the SUT authenticator and the API endpoint for generating SUTs.
The PSM team will implement the PSM integration in a separate effort in the
PSM codebase.

## Design

### High-Level Design

#### Workflows

##### Basic SUT Workflow

The following diagram shows the basic workflow for using a SUT to authenticate
to Conjur. The first step is to call the
`GET /authn-sut/<authenticator-name>/<account>/login` endpoint with the user's
credentials to generate a SUT. The SUT is then passed to the
`POST /authn-sut/<authenticator-name>/<account>/authenticate`
endpoint to authenticate the user to Conjur and retrieve a short-lived auth
token.

![Basic SUT Workflow](./sut.png)

##### 3rd Party Client Workflow

The following diagram shows the workflow for using a SUT to authenticate to
Conjur on behalf of a 3rd party client. The first step is to call the
`GET /authn-sut/<authenticator-name>/<account>/login` endpoint with the user's
credentials to generate a SUT. The SUT is then handed off to the 3rd party
client. The 3rd party client then calls the
`POST /authn-sut/<authenticator-name>/<account>/authenticate`
endpoint with the SUT to authenticate the user to Conjur and retrieve a
short-lived auth token. This way the 3rd party client never has access to the
user's credentials.

![3rd Party Client Workflow](./sut_3rd_party.png)

##### PSM Integration Workflow

The following diagram shows the workflow for using a SUT to authenticate to
Conjur via the PSM integration. The first step is to call the
`GET /authn-sut/<authenticator-name>/<account>/login` endpoint with the user's
credentials to generate a SUT. The SUT is then passed to the Conjur UI via a URL
parameter: `GET <conjur-ui-url>/ui/callback?sut=<sut>`. The Conjur UI then calls
the `POST /authn-sut/<authenticator-name>/<account>/authenticate` endpoint with
the SUT to authenticate the user to Conjur and retrieve a short-lived auth
token. The Conjur UI then starts a session for the user.

![PSM Integration Workflow](./psm.png)

<!-- TODO: Workflow State Visibility, Log messages, Audit logs -->

#### Policy

As with other authenticators, the SUT authenticator will be disabled by default.
It will be enabled by creating an authenticator policy resource in Conjur and
adding it to the list of enabled authenticators in the Conjur configuration, for
example in the `CONJUR_AUTHENTICATORS` environment variable.

The authenticator webservice must be declared in Conjur policy:

```yml
- !policy
id: conjur/authn-sut/<authenticator-name>
body:
- !webservice

- !group clients

- !permit
role: !group clients
privilege: [ read, authenticate ]
resource: !webservice
```
and the `clients` group can be used to entitle a user(s) to use the
authenticator:

```yml
- !grant
role: !group conjur/authn-sut/<authenticator-name>/clients
member: !user <username>
```

#### API

We will need two new API endpoints for the SUT authenticator:

##### `GET /authn-sut/<authenticator-name>/<account>/login`

This endpoint will be used to generate a SUT for a user. The user will provide
their username and password (or API key) in the request body. The endpoint will
return a SUT that can be used to authenticate the user to Conjur.

The format of the URL matches the existing authenticator endpoint for
authn-ldap.

##### `POST /authn-sut/<authenticator-name>/<account>/authenticate`

This endpoint will be used to authenticate a user to Conjur using a SUT. The
user will provide the SUT in the request body. The endpoint will return a
short-lived auth token.

The format of the URL matches the existing authenticator endpoint for
authn-ldap.

### Low Level Design

#### Data Model

The SUT will be a cryptographically secure, random string. It will be generated
by the Conjur server and stored in the database. The SUT will be associated with
the user and expiration time. The SUT will be marked as used once it is utilized
to authenticate the user to Conjur.

When we store the SUT in the database, we will store a hash of the SUT instead
of the SUT itself. This will prevent an attacker with access to the database
from being able to use the SUTs to authenticate to Conjur. The SUT will be
hashed using a cryptographically secure hash function, such as SHA-256.
When a user presents a SUT to authenticate to Conjur, we will hash the SUT and
compare it to the hash stored in the database.

##### SUT Format

We cannot use JWTs for the SUT as we need the ability to revoke the SUT after it
is used, a feature not easily implemented with JWTs. This would make it
impossible to prevent replay attacks.

##### Open Questions

- Is it possible to restrict use of the SUT to a specific IP range (like with
hostfactory tokens) or other criteria to limit risk if the SUT is leaked?
- Is it better to actually delete the SUT from the database once it is used or
to just mark it as used?
- Is it better to store a `used_at` timestamp or a boolean `used` flag?
- Should the SUT expiration be configurable (via policy) or should it be a fixed
value? What should the default expiration be? (30 seconds?)

##### Example Database Table

| id | role_id | guid_hash | expires_at | used_at |
|----|---------|-----------|------------|---------|
| 1 | user:john.doe | lkduj... | 2023-09-28 12:08:23 | NULL |
| 2 | user:demo.user | 2k1g2... | 2023-09-28 12:09:45 | 2023-09-28 12:09:10 |

For this example, we would need a migration to add the `authn_sut_tokens` table.
That would look something like this:

```ruby
Sequel.migration do
change do
create_table :authn_sut_tokens do
primary_key :id
foreign_key :role_id, :roles, type: String, null: false, on_delete: :cascade
String :guid_hash, null: false, unique: true
DateTime :expires_at, null: false
DateTime :used_at
end
end
end
```

#### Authenticator

The SUT authenticator will be implemented as a new authenticator plugin. The
implementation will follow the existing authenticator plugin pattern, as
documented in [AUTHENTICATORS.md](../AUTHENTICATORS.md)

## Security

Due to the fact that this feature will be used to authenticate to Conjur, it is
critical that the implementation is secure. Threat modeling should be performed
before implementation begins to identify potential security issues and ensure
that they are addressed. There should be an additional security review of the
implementation before it is merged.

Much of the security of this feature will be provided by the underlying
authenticator architecture, so we only need to be concerned with the security of
the SUT and the implementation of the SUT authenticator plugin.

## Testing

### Unit Tests

Unit tests should cover virtually all lines of code in the implementation.

### Integration Tests

Integration tests should cover the following scenarios

| Scenario | Path Type | Test Purpose | Failure Scenarios | Details |
|----------|-----------|--------------|-------------------|---------|
| Generate SUT | Happy | Verify that a SUT can be generated for a user | | |
| Generate SUT - Invalid credentials | Sad | Verify that a SUT cannot be generated for a user with invalid credentials | | |
| Generate SUT - Invalid authenticator | Sad | Verify that a SUT cannot be generated for a user with an invalid authenticator | | |
| Generate SUT - Disabled authenticator | Sad | Verify that a SUT cannot be generated for a user with a disabled authenticator | | |
| Generate SUT - Authenticator not enabled for user | Sad | Verify that a SUT cannot be generated for a disabled user | | |
| Authenticate with SUT | Happy | Verify that a user can authenticate to Conjur with a SUT | | |
| Authenticate with SUT - Invalid SUT | Sad | Verify that a user cannot authenticate to Conjur with an invalid SUT | | |
| Authenticate with SUT - Expired SUT | Sad | Verify that a user cannot authenticate to Conjur with an expired SUT | | |
| Authenticate with SUT - Used SUT | Sad | Verify that a user cannot authenticate to Conjur with a used SUT | | |
| Authenticate with SUT - Invalid authenticator | Sad | Verify that a user cannot authenticate to Conjur with an invalid authenticator | | |
| Authenticate with SUT - Disabled authenticator | Sad | Verify that a user cannot authenticate to Conjur with a disabled authenticator | | |
| Authenticate with SUT - Authenticator not enabled for user | Sad | Verify that a user cannot authenticate to Conjur with a disabled user | | |

## Project Cost & Schedule

For the following table, "Effort" is estimated in terms of developer days. "Risk"
is an estimate of the risk of missing said estimate. Low risk means high likelihood
of hitting the estimate, while high risk means low likelihood of hitting the estimate.

| Task | Effort | Risk |
|------|--------|------|

<!-- TODO: Task list -->
Loading

0 comments on commit f8256db

Please sign in to comment.