|
1 | 1 | # QAToolKit Authentication library
|
2 |
| -[](https://github.com/qatoolkit/qatoolkit-auth-net/actions) |
| 2 | +[](https://github.com/qatoolkit/qatoolkit-auth-net/actions) |
3 | 3 | [](https://github.com/qatoolkit/qatoolkit-auth-net/security/code-scanning)
|
4 | 4 | [](https://sonarcloud.io/dashboard?id=qatoolkit_qatoolkit-auth-net)
|
5 | 5 | [](https://www.nuget.org/packages/QAToolKit.Auth/)
|
6 | 6 |
|
7 | 7 | ## Description
|
8 |
| -`QAToolKit.Auth` is a .NET Standard 2.1 library, that contains core objects and functions of the toolkit. It's normally not used as a standalone library but is a dependency for other QAToolKit libraries. |
| 8 | +`QAToolKit.Auth` is a .NET Standard 2.1 library, that retrieves the JWT access tokens from different identity providers. |
| 9 | + |
| 10 | +Currently it supports next Identity providers and Oauth2 flows: |
| 11 | +- `Keycloak`: Library supports Keycloak [client credentials flow](https://tools.ietf.org/html/rfc6749#section-4.4) or `Protection API token (PAT)` flow. Additionally you can replace the PAT with user token by exchanging the token. |
9 | 12 |
|
10 | 13 | Supported .NET frameworks and standards: `netstandard2.0`, `netstandard2.1`, `netcoreapp3.1`, `net5.0`
|
11 | 14 |
|
12 |
| -## 1. HttpRequest functions |
13 |
| -HttpRequest object is one of the main objects that is shared among the QA Toolkit libraries. `QAToolKit.Core` library contains `HttpRequestTools` which can manipulate the HttpRequest object. |
| 15 | +## 1. Keycloak support |
14 | 16 |
|
15 |
| -For example URL, header and Body generators: `HttpRequestUrlGenerator`, `HttpRequestBodyGenerator` and `HttpRequestHeaderGenerator`. |
| 17 | +Keycloak support is limited to the `client credential` or `Protection API token (PAT)` flow in combination with `token exchange`. |
16 | 18 |
|
17 |
| -### 1.1. HttpRequestUrlGenerator |
18 |
| -This is a method that will accept key/value pairs for replacement of placeholders in the `HttpRequest` object. Replacement object are stored in a dictionary, which `prevents mistakes with duplicated keys`. |
19 |
| -Also dictionary keys are case insensitive when looking for values to replace. |
| 19 | +### 1.1. Client credential flow |
20 | 20 |
|
21 |
| -```csharp |
22 |
| -options.AddReplacementValues(new Dictionary<string, object> { |
23 |
| - { |
24 |
| - "version", |
25 |
| - "1" |
26 |
| - }, |
27 |
| - { |
28 |
| - "parentId", |
29 |
| - "4" |
30 |
| - } |
31 |
| -}); |
| 21 | +A mocked request below is sent to the Keycloak endpoint, and the PAT token is retrieved: |
| 22 | + |
| 23 | +```bash |
| 24 | +curl -X POST \ |
| 25 | + -H "Content-Type: application/x-www-form-urlencoded" \ |
| 26 | + -d 'grant_type=client_credentials&client_id=${client_id}&client_secret=${client_secret}' \ |
| 27 | + "http://localhost:8080/auth/realms/${realm_name}/protocol/openid-connect/token" |
32 | 28 | ```
|
33 | 29 |
|
34 |
| -In the example above we say: "Replace `{version}` and {parentId} placeholders in Path and URL parameters and JSON body models." |
| 30 | +Read [more](https://www.keycloak.org/docs/latest/authorization_services/#_service_protection_whatis_obtain_pat) here in the Keycloak documentation. |
35 | 31 |
|
36 |
| -In other words, if you have a test API endpoint like this: https://api.demo.com/v{version}/categories?parent={parentId} that will be set to https://api.demo.com/v1/categories?parent=4. |
| 32 | +Now let's retrive a PAT token with QAToolKit Auth libraray: |
37 | 33 |
|
38 |
| -That, does not stop there, you can also populate JSON request bodies. |
| 34 | +```csharp |
| 35 | +var auth = new KeycloakAuthenticator(options => |
| 36 | +{ |
| 37 | + options.AddClientCredentialFlowParameters( |
| 38 | + new Uri("https://my.keycloakserver.com/auth/realms/realmX/protocol/openid-connect/token"), |
| 39 | + "my_client", |
| 40 | + "client_secret"); |
| 41 | +}); |
39 | 42 |
|
40 |
| -### 1.2. HttpRequestBodyGenerator |
| 43 | +var token = await auth.GetAccessToken(); |
| 44 | +``` |
41 | 45 |
|
42 |
| -For example if you set the replacement value to stringified json: |
| 46 | +### 1.2. Client credential flow with token exchange |
43 | 47 |
|
44 |
| -```csharp |
45 |
| -options.AddReplacementValues(new Dictionary<string, object> { |
46 |
| - { |
47 |
| - "id", |
48 |
| - "100" |
49 |
| - }, |
50 |
| - { |
51 |
| - "category", |
52 |
| - "{\"id\":1,\"name\":\"dog\"}" |
53 |
| - } |
54 |
| -}); |
| 48 | +If you want to replace the PAT token with user token, you can additionally specify a username. A mocked request looks like this: |
| 49 | + |
| 50 | +```bash |
| 51 | +curl -X POST \ |
| 52 | + -H "Content-Type: application/x-www-form-urlencoded" \ |
| 53 | + -d 'grant_type=urn:ietf:params:oauth:grant-type:token-exchange&client_id=${client_id}&client_secret=${client_secret}&subject_token=eyJhbGciOiJI...&requested_subject=myuser@users.com' \ |
| 54 | + "http://localhost:8080/auth/realms/${realm_name}/protocol/openid-connect/token" |
55 | 55 | ```
|
56 |
| -than the parent model object will be replaced with the stringified json above. |
57 | 56 |
|
58 |
| -What happend behind the curtains, the model proxy class is generated, which is then used to Deserialized the JSON into the object. |
59 |
| -`HttpRequest` list is then scanned and values are properly replaced. |
| 57 | +As you see it has a different `grant_type` and additionally 2 more properties in the URL; PAT token (`subject_token`) and userName for which we want to replace the token (`requested_subject`). |
60 | 58 |
|
61 |
| -### 1.3. HttpRequestHeaderGenerator |
| 59 | +```csharp |
| 60 | +var auth = new KeycloakAuthenticator(options => |
| 61 | +{ |
| 62 | + options.AddClientCredentialFlowParameters( |
| 63 | + new Uri("https://my.keycloakserver.com/auth/realms/realmX/protocol/openid-connect/token"), |
| 64 | + "my_client", |
| 65 | + "client_secret"); |
| 66 | + options.AddUserNameForImpersonation("myuser@users.com"); |
| 67 | +}); |
62 | 68 |
|
63 |
| -To-do |
| 69 | +var token = await auth.GetAccessToken(); |
| 70 | +``` |
64 | 71 |
|
65 | 72 | ## To-do
|
66 | 73 |
|
67 | 74 | - **This library is an early alpha version**
|
68 |
| -- `HttpRequestHeaderGenerator` is missing implementation. |
69 |
| -- `HttpRequestBodyGenerator` need to cover the whole spectrum of object tipes. Currently it's missing arrays, and nested objects. It's on the priority list. |
| 75 | +- Add more providers identity providers. |
| 76 | +- Add more OAuth2 flows. |
70 | 77 |
|
71 | 78 | ## License
|
72 | 79 |
|
|
0 commit comments