Skip to content

Commit

Permalink
fix: Refactor in order to include source of token issuing
Browse files Browse the repository at this point in the history
  • Loading branch information
Paula-Kli committed Oct 5, 2023
1 parent ed5f6f4 commit 2512b73
Show file tree
Hide file tree
Showing 13 changed files with 153 additions and 68 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,14 @@


def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.create_table(
"basic_auth_token",
sa.Column("id", sa.Integer(), autoincrement=True, nullable=False),
sa.Column("user_id", sa.Integer(), nullable=False),
sa.Column("hash", sa.String(), nullable=False),
sa.Column("expiration_date", sa.Date(), nullable=False),
sa.Column("description", sa.String(), nullable=False),
sa.Column("source", sa.String(), nullable=False),
sa.ForeignKeyConstraint(
["user_id"],
["users.id"],
Expand All @@ -39,4 +39,3 @@ def upgrade():
["id"],
unique=False,
)
# ### end Alembic commands ###
11 changes: 9 additions & 2 deletions backend/capellacollab/users/tokens/crud.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,22 @@


def create_token(
db: orm.Session, user_id: int, description: str
db: orm.Session,
user_id: int,
description: str,
expiration_date: datetime.date | None,
source: str | None,
) -> tuple[models.DatabaseUserTokenModel, str]:
password = credentials.generate_password(32)
ph = argon2.PasswordHasher()
if not expiration_date:
expiration_date = datetime.datetime.now() + datetime.timedelta(days=30)
token_data = models.DatabaseUserTokenModel(
user_id=user_id,
hash=ph.hash(password),
expiration_date=datetime.datetime.now() + datetime.timedelta(days=30),
expiration_date=expiration_date,
description=description,
source=source,
)
db.add(token_data)
db.commit()
Expand Down
1 change: 1 addition & 0 deletions backend/capellacollab/users/tokens/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,4 @@ class DatabaseUserTokenModel(database.Base):
hash: orm.Mapped[str]
expiration_date: orm.Mapped[datetime.date]
description: orm.Mapped[str]
source: orm.Mapped[str]
10 changes: 8 additions & 2 deletions backend/capellacollab/users/tokens/routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,15 @@ def create_token_for_user(
user_injectables.get_own_user
),
db: orm.Session = fastapi.Depends(database.get_db),
description: str = fastapi.Body(),
body: dict = fastapi.Body(),
):
_, password = crud.create_token(db, user.id, description)
_, password = crud.create_token(
db,
user.id,
body["token_description"],
body["expiration_date"],
body["source"],
)
return password


Expand Down
50 changes: 27 additions & 23 deletions docs/user/docs/tokens.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,53 +3,57 @@
~ SPDX-License-Identifier: Apache-2.0
-->

# Token Authentication
# Authentication with Personal Access Tokens (PAT)

To authenticate against the API you can either use a Bearer token (which the
browser usually uses) or authenticate with a longer lived basic authentication
token which can be used e.g. in scripts.
browser usually uses) or authenticate with a longer lived personal access token
tokenn (PAT) which can be used e.g. in scripts.

## Token Creation
## PAT Creation

To create a Token you can go to Profile > Token and insert a short description
to create a token.
To create a personal access token (PAT) you can go to Profile > Token and
insert a short description to create a token.

<!-- prettier-ignore -->

!!! info The password which is generated can only be copied. Make sure you save
it - you won't be able to access it again

## Token Scope
## PAT Scope

Basic authentication token have the same scope as the bearer token.
Personal access token have almost the same scope as the user who created it. It
is therefore important that you never pass on the token and treat it
responsibly. If you feel that the token has been lost, revoke it immediately
and inform the Systems Engineering Toolchain team.

<!-- prettier-ignore -->
!!! warning
As currently Basic Authentication token have the same scope as you logged in your browser they can act as your user. Please do not share the password and if the information gets lost please revoke the token as soon as possible.

## Revoke a Token
## Revoke a PAT

In order to revoke a token go to Profile > Token. There you can see a list of
all tokens that belong to your user. Clicking on the trash symbol you can
delete a token which will no longer be valid to authenticate.

## Token Usage
## PAT Usage

The token created is a basic authentication token. There are different ways to
The token created is a personal access token. There are different ways to
authenticate with that against the Collaboration Manager API. One example is:

```zsh
curl --basic -u yourUsername:yourPassword https://baseurl/api/v1/users/current/tokens
curl --basic -u <username>:<token> https://<baseURL>/api/v1/users/current/tokens
```

or to work with the diagram cache
or to work with the diagram cache of Capellambse. Capellambse is an
implementation of the capella modelling tool using python and lets you read and
write models. For more information have a look at the
[documentation](https://dsd-dbs.github.io/py-capellambse/) or the
[github repository](https://github.com/DSD-DBS/py-capellambse).

```python
capellambse.model.MelodyModel(
path="path to the model on your machine",
diagram_cache={
"path": "https://baseurl/api/projects/[yourProjectSlug]/[yourModelName]/diagrams/%s",
"username": "yourUsername",
"password": "yourPassword",
})
path="path to the model on your machine",
diagram_cache={
"path": "https://<baseURL>/api/projects/[yourProjectSlug]/[yourModelSlug]/diagrams/%s",
"username": "<username>",
"password": "<token>",
}
)
```
2 changes: 1 addition & 1 deletion docs/user/mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ nav:
- Getting Started:
- Overview: getting-started/overview.md
- Introduction to Capella: getting-started/capella-intro.md
- Authentication: tokens.md
- Projects:
- Get access to a project: projects/access.md
- Add a user to a project: projects/add-user.md
Expand Down Expand Up @@ -64,6 +63,7 @@ nav:
- Create an alert: additional/alerts/create.md
- Delete an alert: additional/alerts/delete.md
- User Management: users.md
- Authentication: tokens.md
- Release Notes: release-notes.md
- About: about.md

Expand Down
2 changes: 1 addition & 1 deletion frontend/src/app/app-routing.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -434,7 +434,7 @@ const routes: Routes = [
},
{
path: 'tokens',
data: { breadcrumb: 'tokens' },
data: { breadcrumb: 'Tokens' },
component: BasicAuthTokenComponent,
},
],
Expand Down
4 changes: 4 additions & 0 deletions frontend/src/app/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { MatBadgeModule } from '@angular/material/badge';
import { MatButtonToggleModule } from '@angular/material/button-toggle';
import { MatRippleModule } from '@angular/material/core';
import { MatNativeDateModule } from '@angular/material/core';
import { MatDatepickerModule } from '@angular/material/datepicker';
import { MatDialogModule, MatDialogRef } from '@angular/material/dialog';
import { MatExpansionModule } from '@angular/material/expansion';
import { MatIconModule } from '@angular/material/icon';
Expand Down Expand Up @@ -236,13 +238,15 @@ import { SettingsComponent } from './settings/settings.component';
MatButtonToggleModule,
MatCardModule,
MatCheckboxModule,
MatDatepickerModule,
MatDialogModule,
MatExpansionModule,
MatFormFieldModule,
MatIconModule,
MatInputModule,
MatListModule,
MatMenuModule,
MatNativeDateModule,
MatPaginatorModule,
MatProgressBarModule,
MatProgressSpinnerModule,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,20 @@ export class TokenService {
});
}

createToken(tokenDescription: string): Observable<string> {
createToken(
token_description: string,
expiration_date: Date | null,
source: string
): Observable<string> {
if (!expiration_date) {
expiration_date = new Date();
}
const password = this.http
.post<string>(
environment.backend_url + `/users/current/token`,
tokenDescription
)
.post<string>(environment.backend_url + `/users/current/token`, {
token_description,
expiration_date,
source,
})
.pipe(tap(() => this.loadTokens()));

return password;
Expand All @@ -50,5 +58,6 @@ export class TokenService {
export type Token = {
description: string;
expiration_date: string;
source: string;
id: number;
};
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,10 @@
* SPDX-FileCopyrightText: Copyright DB Netz AG and the capella-collab-manager contributors
* SPDX-License-Identifier: Apache-2.0
*/

.border {
margin-right: 5px;
padding: 5px;
border: 2px solid var(--primary-color);
border-radius: 5px;
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,24 +3,53 @@
~ SPDX-License-Identifier: Apache-2.0
-->

<div class="mb-10 items-center">
<h2>Basic Authentication Token</h2>
<div class="mb-2 items-center">
<h2>Personal Access Tokens</h2>
</div>
<div class="input-container mb-10">
<div>
To create a Personal Access Token please choose an expiration date and provide
a short description.
<div class="items-center">
<input
matInput
type="text"
[(ngModel)]="tokenDescription"
placeholder="Token description"
class="mr-10"
/>
<form [formGroup]="tokenInput">
<mat-form-field appearance="outline" class="mr-2 w-9/12">
<mat-label>Token description</mat-label>
<textarea
matInput
placeholder="Please shortly describe the purpose of the token"
formControlName="tokenDescription"
></textarea>
<mat-hint align="start"
><strong
>Note: The created token has the same permissions as you have when
being logged in.</strong
></mat-hint
>
</mat-form-field>
<div class="flex items-end">
<mat-form-field class="mr-10">
<mat-label>Choose an expiration date</mat-label>
<input
matInput
[min]="minDate"
[max]="maxDate"
[matDatepicker]="picker"
[formControl]="date"
/>
<mat-hint>MM/DD/YYYY</mat-hint>
<mat-datepicker-toggle
matIconSuffix
[for]="picker"
></mat-datepicker-toggle>
<mat-datepicker #picker></mat-datepicker>
</mat-form-field>
</div>
</form>
<button
class="self-end mt-auto text-white"
(click)="createNewToken(tokenDescription)"
[disabled]="!tokenDescription"
(click)="createNewToken()"
color="primary"
mat-raised-button
[disabled]="tokenInput.invalid"
>
Create Token
</button>
Expand All @@ -43,15 +72,15 @@ <h2>Basic Authentication Token</h2>
mat-mini-fab
matTooltip="Show token"
>
<mat-icon> blur_off</mat-icon>
<mat-icon>blur_off</mat-icon>
</button>
<button
*ngIf="passwordRevealed"
(click)="this.passwordRevealed = false"
mat-mini-fab
matTooltip="Hide token"
>
<mat-icon> blur_on</mat-icon>
<mat-icon>blur_on</mat-icon>
</button>
<div class="text-red-600 mt-2">
Make sure you save the token - you won't be able to access it again.
Expand All @@ -63,15 +92,16 @@ <h2>Token overview</h2>
<mat-card *ngFor="let token of tokenService.tokens$ | async">
<mat-card-content>
Description: {{ token.description }} <br />
Expiration date: {{ token.expiration_date | date }}
Expiration date: {{ token.expiration_date | date }} <br />
Creation location: {{ token.source }}
<div *ngIf="isTokenExpired(token.expiration_date)">
<mat-icon color="warn" class="align-middle">warning</mat-icon>
<span class="align-middle text-red-600">This token has expired!</span>
<span class="text-red-600">This token has expired!</span>
</div>
</mat-card-content>
<button (click)="deleteToken(token)" mat-raised-button>
<mat-icon color="warn" class="align-middle">delete</mat-icon>
<span class="align-middle">Revoke token</span>
<span>Revoke token</span>
</button>
</mat-card>
</ng-container>
Expand Down
Loading

0 comments on commit 2512b73

Please sign in to comment.