Skip to content

Commit 0e61950

Browse files
authored
Merge pull request #1 from SafinWasi/agama-lab-branch
Full functionality
2 parents 9c7ddad + cd668ab commit 0e61950

File tree

13 files changed

+2297
-581
lines changed

13 files changed

+2297
-581
lines changed

README.md

Lines changed: 138 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,139 @@
1-
# agama-typekey
2-
An Agama flow designed to authenticate against the Typekey API to test behavioral metrics
3-
4-
## Setup
5-
6-
Modify the configuration with the following values:
7-
8-
```json
9-
...
10-
"configs": {
11-
"io.jans.typekey": {
12-
"keystoreName": "", // name of keystore file
13-
"keystorePassword": "", // password of keystore file
14-
"orgId": "", // org_id of the SCAN account to use
15-
"clientId": "", // Client ID obtained from DCR
16-
"clientSecret": "", // Client secret obtained from DCR
17-
"authHost": "https://account-dev.gluu.cloud", // Authorization server
18-
"scanHost": "https://cloud-dev.gluu.cloud" // SCAN host
1+
# Agama Typekey Project
2+
3+
<!-- These are statistics for this repository-->
4+
[![Contributors][contributors-shield]][contributors-url]
5+
[![Forks][forks-shield]][forks-url]
6+
[![Stargazers][stars-shield]][stars-url]
7+
[![Issues][issues-shield]][issues-url]
8+
[![Apache License][license-shield]][license-url]
9+
10+
This project allows you to record behavioral keystroke data and use it as a second factor of authentication by leveraging the Typekey API.
11+
12+
## How it works at a glance
13+
14+
The project contains one flow: `org.gluu.agama.typekey`. When this is launched, the user is first asked for the username. If the user exists and has not been enrolled, a random phrase is chosen from the list of configured phrases and stored in persistence. Then the user is asked to type the phrase, and the website records keystroke data for that phrase. This data is sent to the Typekey API to enroll the user and used as the first factor. If the user is being enrolled or Typekey API denies authentication, password is used as the second factor.
15+
16+
### Requirements
17+
18+
1. A running instance of Jans Auth Server
19+
1. A new column in `jansdb.jansPerson` to store the phrase metadata in
20+
1. A SCAN subscription. Please visit [https://gluu.org/agama-lab] and sign up for a free SCAN subscription, which gives you 500 credits. Each successful Typekey API call costs 25 credits.
21+
22+
### Add column to database
23+
24+
These instructions are for MySQL. Please follow the [documentation](https://docs.jans.io/v1.0.22/admin/reference/database/) for your persistence type.
25+
26+
1. Log into the server running Jans
27+
2. Log into MySQL with a user that has permission to operate on `jansdb`
28+
3. Add the column:
29+
30+
```sql
31+
ALTER TABLE jansdb.jansPerson ADD COLUMN typekeyData JSON NULL;
32+
```
33+
34+
4. Restart MySQL and Auth Server to load the changes:
35+
36+
```
37+
systemctl restart mysql jans-auth
38+
````
39+
40+
### Dynamic Client Registration
41+
42+
In order to call the Typekey API, you will need an OAuth client. Once you have a SCAN subscription on Agama Lab, navigate to `Market` > `SCAN` and create an SSA with the software claim `typekey` and an appropriate lifetime. Your client will expire after that time. Once this is done, note down the base64 encoded string, and send a dynamic client registration request to `https://account.gluu.org/jans-auth/restv1/register` to obtain a client ID and secret. You will need this to configure the Typekey flow. Jans Tarp has functionality to automate the registration process.
43+
44+
- [Dynamic Client Registration specification](https://www.rfc-editor.org/rfc/rfc7591#section-3.1)
45+
- [Jans Tarp](https://github.com/JanssenProject/jans/tree/main/demos/jans-tarp)
46+
47+
### Deployment
48+
49+
Download the latest [agama-typekey.gama](https://github.com/GluuFederation/agama-typekey/releases/latest/download/agama-typekey.gama) file and deploy it in Auth Sever.
50+
51+
Follow the steps below:
52+
53+
- Copy (SCP/SFTP) the gama file of this project to a location in your `Jans Server`
54+
- Connect (SSH) to your `Jans Server` and open TUI: `python3 /opt/jans/jans-cli/jans_cli_tui.py`
55+
- Navigate to the `Agama` tab and then select `"Upload project"`. Choose the gama file
56+
- Wait for about one minute and then select the row in the table corresponding to this project
57+
- Press `d` and ensure there were not deployment errors
58+
- Pres `ESC` to close the dialog
59+
60+
### Configure Typekey
61+
62+
- Open TUI and navigate to `Agama`
63+
- Select the deployed project and hit `c`
64+
- Select `Export sample configuration` and select a directory and a filename
65+
- Open the file in an editor
66+
67+
```
68+
{
69+
"org.gluu.agama.typekey": {
70+
"keystoreName": "",
71+
"keystorePassword": "",
72+
"orgId": "",
73+
"clientId": "",
74+
"clientSecret": "",
75+
"authHost": "https://account.gluu.org",
76+
"scanHost": "https://cloud.gluu.org"
1977
}
20-
}
21-
```
78+
}
79+
```
80+
81+
### Configuration details
82+
83+
- `keystoreName` and `keystorePassword` are optional, in case you want to include a signature when sending the Typekey data. Leave them as blank otherwise.
84+
- `orgId` is the organization ID that can be obtained by decoding the software statement JWT and looking at the `org_id` claim (You may use `https://jwt.io` to decode the SSA).
85+
- `clientId` and `clientSecret` are the client credentials obtained from Dynamic Client Registration
86+
- `authHost` and `scanHost` can be left as is
87+
88+
- We go back to the TUI and click on `Import Configuration` and select the modified configuration file with our parameters.
89+
- With this, our `agama project` is now configured and we can start testing.
90+
91+
## Testing
92+
93+
You'll need an OpenID Connect test RP. You can try [oidcdebugger](https://oidcdebugger.com/),
94+
[jans-tarp](https://github.com/JanssenProject/jans/tree/main/demos/jans-tarp)
95+
or [jans-tent](https://github.com/JanssenProject/jans/tree/main/demos/jans-tent).
96+
97+
Launch an authorization flow with parameters `acr_values=agama&agama_flow=org.gluu.agama.typekey` with your chosen RP.
98+
99+
Check out this video to see an example of **agama-typekey** in action:
100+
101+
# Contributors
102+
103+
<table>
104+
<tr>
105+
<td align="center" style="word-wrap: break-word; width: 150.0; height: 150.0">
106+
<a href=https://github.com/SafinWasi>
107+
<img src=https://avatars.githubusercontent.com/u/6601566?v=4 width="100;" style="border-radius:50%;align-items:center;justify-content:center;overflow:hidden;padding-top:10px" alt=SafinWasi/>
108+
<br />
109+
<sub style="font-size:14px"><b>SafinWasi</b></sub>
110+
</a>
111+
</td>
112+
</tr>
113+
</table>
114+
115+
# License
116+
117+
This project is licensed under the [Apache 2.0](https://github.com/GluuFederation/agama-typekey/blob/main/LICENSE)
118+
119+
<!-- This are stats url reference for this repository -->
120+
121+
[contributors-shield]: https://img.shields.io/github/contributors/GluuFederation/agama-typekey.svg?style=for-the-badge
122+
123+
[contributors-url]: https://github.com/GluuFederation/agama-typekey/graphs/contributors
124+
125+
[forks-shield]: https://img.shields.io/github/forks/GluuFederation/agama-typekey.svg?style=for-the-badge
126+
127+
[forks-url]: https://github.com/GluuFederation/agama-typekey/network/members
128+
129+
[stars-shield]: https://img.shields.io/github/stars/GluuFederation/agama-typekey?style=for-the-badge
130+
131+
[stars-url]: https://github.com/GluuFederation/agama-typekey/stargazers
132+
133+
[issues-shield]: https://img.shields.io/github/issues/GluuFederation/agama-typekey.svg?style=for-the-badge
134+
135+
[issues-url]: https://github.com/GluuFederation/agama-typekey/issues
136+
137+
[license-shield]: https://img.shields.io/github/license/GluuFederation/agama-typekey.svg?style=for-the-badge
138+
139+
[license-url]: https://github.com/GluuFederation/agama-typekey/blob/main/LICENSE

code/org.gluu.agama.typekey.flow

Lines changed: 36 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,44 @@
11
Flow org.gluu.agama.typekey
22
Basepath ""
3-
Configs conf
4-
Log "@info " Starting Typekey Authentication
5-
user = {}
6-
password = {}
7-
typekey = {}
8-
user = RRF "typekey/username.ftlh" user
3+
Log "@info " Starting typekey authentication
94
idp = Call org.gluu.agama.typekey.IdentityProcessor#new
5+
tk = Call org.gluu.agama.typekey.Typekey#new conf
6+
user = RRF "typekey/username.ftlh"
107
userData = Call idp accountFromUsername user.username
118
When userData.empty is true
12-
it_mqfld = {success:false, error: "Account not found"}
13-
Finish it_mqfld
14-
tk = Call org.gluu.agama.typekey.Typekey#new conf
9+
it_aixno = {success:false, error: "User not found"}
10+
Finish it_aixno
1511
enrolled = Call idp enrolled user.username
1612
When enrolled is false
1713
random_usecase = Call tk getRandomUseCase
18-
phrase_map = Call tk getPhraseMap random_usecase
19-
res = Call idp enroll user.username phrase_map
20-
it_dhkcc = {success:true, data: { userId: user.username}}
21-
Finish it_dhkcc
14+
phrase_map = Call tk generateTypekeyData random_usecase
15+
dummy = Call idp enroll user.username phrase_map
16+
phrase = phrase_map.phrase
17+
use_case = random_usecase
18+
When enrolled is true
19+
typekey_data = Call idp getTypekeyData user.username
20+
phrase = typekey_data.phrase
21+
use_case = typekey_data.useCase
22+
phraseDict = {phrase:phrase}
23+
phraseData = RRF "typekey/phrase.ftlh" phraseDict
24+
typekey_result = Call tk validateKeystrokes user.username phraseData.phrase_data use_case
25+
When typekey_result.status is "Enrollment"
26+
password = RRF "typekey/password.ftlh"
27+
authenticated = Call idp authenticate user.username password.pwd
28+
When authenticated is true
29+
Call tk notifyKeystrokes user.username typekey_result.track_id
30+
it_ouffo = {success:true, data: { userId: user.username}}
31+
Finish it_ouffo
32+
it_wqexb = {success:false, error: "Authentication failed"}
33+
Finish it_wqexb
34+
When typekey_result.status is "Approved"
35+
it_vgryb = {success:true, data: { userId: user.username}}
36+
Finish it_vgryb
37+
password = RRF "typekey/password.ftlh"
38+
authenticated = Call idp authenticate user.username password.pwd
39+
When authenticated is true
40+
Call tk notifyKeystrokes user.username typekey_result.track_id
41+
it_txptw = {success:true, data: { userId: user.username}}
42+
Finish it_txptw
43+
it_zqjxb = {success:false, error: "Password and typekey failed"}
44+
Finish it_zqjxb

0 commit comments

Comments
 (0)