Introduction to OIDC Provide Curity From Installing to Auth Flows
As OIDC is becoming more and more popular, I decided to try as many free
OIDC providers as I can just to see how they works. In my previous post I show you some basics of Keycloak
. In this post I will follow the same style to give you a brief introduction to Curity.
Curity is not entirely a free IDP, you must obtain a license to use this product. You should be able to obtain a community license using your company’s email address.
Please make sure you have a license before reading further.
Installation with docker
As usual, I will use Traefik as reverse proxy to handle TLS and expose port 80 and 443 to the public.
Installation is pretty straight forward. Because we must use TLS to communicate with Curity, I need to tell Traefik to ignore TLS verification. To do that I need to useserversTransports
and it is only available when we are using file
and Kubernetes CRD
providers.[^1]
Install Traefik
If you don’t know how to use Traefik with file provider, please check my previous post. I even made a video to show you how it works.
Here are all the files you need for the demo.
Please note this is meant to be used on a server which means it has http redirect to https and it request valid SSL from let’sEncrypt automatically. If you use it for local testing, you need to modify the settings to not obtain SSL and maybe stop the redirect.
Create files
1
2
3
4
5
6mkdir -p data/configurations
touch docker-compose.yaml
touch data/traefik.yaml
touch data/acme.json
touch data/configurations/dynamic.yaml
chmod 600 data/acme.jsondock-compose.yaml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24version: '2.1'
services:
traefik:
image: traefik:2.5
container_name: traefik
restart: always
security_opt:
- no-new-privileges:true
ports:
- 80:80
- 443:443
volumes:
- /etc/localtime:/etc/localtime:ro
- /var/run/docker.sock:/var/run/docker.sock:ro
- ./data/traefik.yaml:/traefik.yaml:ro
- ./data/acme.json:/acme.json
# Add folder with dynamic configuration yaml
- ./data/configurations:/configurations
networks:
- proxy
networks:
proxy:
external: truetraefik.yaml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36api:
dashboard: true
entryPoints:
web:
address: :80
http:
# Remove below 3 lines to stop http -> https redirect
redirections:
entryPoint:
to: websecure
websecure:
address: :443
http:
middlewares:
- secureHeaders@file
- nofloc@file
tls:
certResolver: letsencrypt
pilot:
dashboard: false
providers:
file:
filename: /configurations/dynamic.yaml
certificatesResolvers:
letsencrypt:
acme:
email: [email protected]
storage: acme.json
keyType: EC384
httpChallenge:
entryPoint: webdynamic.yaml
Let me explain this a little bit.
serversTransports
is used to skip upstream TLS verification. Because Curity container is running inside the same network as Traefik, Traefik can find it using its container namecurity
. Port 6749 is for Curity’s admin UI and port 8443 is for the IDP url.1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31http:
serversTransports:
mytransport:
insecureSkipVerify: true
routers:
traefik-dashboard:
service: api@internal
middlewares:
- "user-auth"
rule: "Host(`traefik.yourdomain.com`)"
curity-ui:
service: curity-ui-service
middlewares:
rule: "Host(`curity-ui.yourdomain.com`)"
curity:
service: curity-service
middlewares:
rule: "Host(`curity.yourdomain.com`)"
services:
curity-ui-service:
loadBalancer:
serversTransport: mytransport
servers:
- url: "https://curity:6749"
curity-service:
loadBalancer:
serversTransport: mytransport
servers:
- url: "https://curity:8443"
Install Curity
Installing Curity is pretty easy, you can start an instance with below docker compose file.
1 | version: '2.1' |
Once you’ve started Traefik and Curity, you can reach Curity admin UI at https://curity-ui.yourdomain.com/admin
and Curity endpoint is https://curity.yourdomain.com
.
Start using Curity
Once you can see the Curity log in page, let’s start. The default username is admin
and password is curity
as I set on Curity’s docker-compose.yaml
file above.
First Configuration
It should be pretty straight forward to follow the the prompts to load your license and select default self-signed certificate etc.
You can follow the official video here if you want to see how it is done. Once it is done, you need several steps before you can use it.
Authentication Service
I will only use html form
authenticator to demo the OIDC usage.
- Click
Profiles
->Authentication Service
->Authenticators
New Authenticator
-> Select HTML form with namedemo
- Select
default-account-manager
anddefault-credential-manager
under Account Manager and Credential Manager respectively - Go to
Changes
->commit
->OK
Token Service
General Settings
- Click
Profiles
->Token Service
- Select
default-account-manager
under Account manager. - Click
OpenID Connect
->Configure Endpoints
-> Make sure you enable all the endpoints you need. For easy demo, I enabled all except JWKs URI. - Go to
Changes
->commit
->OK
Create Client
Click
Clients
->+ New Client
-> name asdemo-client
Go to
Capabilities
section and select the flows you want to use. I will select below options.Code flow
client-credentials
Resource Owner Password Flow
Introspection
Token Exchange
There are some settings we need.
- Redirect URIs -> Add
https://localhost/callback
- Allowed Origins -> Add
https://localhost
-> Click Next - Authentication Method-> Select
secret
-> enterdemosecret
as our secret -> Click Next User Authentication
-> selectdemo
-> Click Done
Under Oauth/OpenID Settings, add
openid
to Scope. We will use it for authentication code flow later.Go to
Changes
->commit
->OK
Now we should be able to use client_credential
flows.
(Optional) You can see the token you are getting are opaque tokens. If you prefer to use JWT token, you can go to Token Issuers
and toggle Use Access Token As JWT
to on. When you tried to commit the changes, you will get below error.
1 | Path: /base:profiles/profile{token-service as:oauth-service}/settings/as:authorization-server/client-capabilities/assisted-token |
To solve the issue, click Goto Element
button, toggle Assisted Token
option to off and commit again. You should get access_token
in JWT now.
Create Users
I hate to say it but I think Curity is making user management much more complicated than it should be.
First of all, there is NO WAY you can manage your user from UI. It is quite difficult for users to know what to do to create new users.
Secondly, they are following SCIM
standard for user management but it is not turned on by default. Users must enable it manually.
Thirdly, users can add whatever information they want to a user. This freedom
might cause serious issue if it was not formalised and restricted by the end users. For example, some users have name
and address
added but some don’t. This might cause issue when you try to use map user claims to token. Feel free to read the SCIM RFC if you are interested.
With that being said, if you are using HTML form as authenticator, you have two methods to add users.
Use Browser (Preferred)
This is much easier than the other one, users can go to https://<curity_domain>/authn/registration/<html_authenticator_name>
to register their account on browser. In our example, the URL for registering new user is https://curity.yourdomain.com/authn/registration/demo
.
Use RESTfulAPI to manage users
As I mentioned above, users must add User Management from admin UI first.
Let’s go back to
Profiles
->Token Service
.You should find
+ Add related profile
button at the bottom of left panel. Click that and chooseCreate User Management Profile
.Enter Name
demo-um
and URL Prefix/user-management
, click Nexttoken-service
should be selected under Token Service andNo Authorization Manager
is ticked by default. Nothing need to be change, click Next.Select every
default
option on this page, click NextSelect
default
for Deployment, click NextCommit
Now we can use RESTfulAPI to manage users.
Please note you need an access token from other authentication flow to use the endpoint.
I am using client_credential to get access token in this example.
Let’s say the access_token
I have is 90efd0e2-0ba9-4d64-9598-a293c94d4e65
.
To list all users, we can use below.
1
2
3curl --request GET \
--url https://curity.li.lan/user-management/admin/Users \
--header 'Authorization: Bearer 90efd0e2-0ba9-4d64-9598-a293c94d4e65'To Create a new user. You can use below. Feel free to add/remove any attributes you like.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29curl --request POST \
--url https://curity.li.lan/user-management/admin/Users \
--header 'Authorization: Bearer 90efd0e2-0ba9-4d64-9598-a293c94d4e65' \
--header 'Content-Type: application/json' \
--data '{
"agreeToTerms": "on",
"active": true,
"userName": "<Username>",
"password": "<Password>",
"phoneNumbers": [
{
"value": "<Phone_Number>",
"primary": true
}
],
"emails": [
{
"value": "<Email>",
"primary": true
}
],
"schemas": [
"urn:ietf:params:scim:schemas:core:2.0:User"
],
"name": {
"givenName": "<Given_Name>",
"familyName": "<Family_Name>"
}
}'Delete User. We can get
<User_ID>
from above get all users call and then send a cURL delete request.1
2
3curl --request DELETE \
--url https://curity.li.lan/user-management/admin/Users/<User_ID> \
--header 'Authorization: Bearer 90efd0e2-0ba9-4d64-9598-a293c94d4e65'
Updating a user is even more complicated… I suggest you to delete and re-add the user instead. Please check official doc for more information.
Now we are ready to test the authentication flows.
Authentication flows
I will cover 4 authentication flows in my examples and I’ve already created a user with both username and password as test
.
Password
Password flow as its name suggested is used to authenticate with username and password. Unlike the other IDPs, Curity does not support openid
scope for this flow. Users can’t get an id_token
with it.
1 | curl --request POST \ |
Client credentials
Client credential flow is machine to machine flow. The access_token
returned is bond to the client we created.
1 | curl --request POST \ |
Introspection
Some companies requires the token to be generated locally and user must include the access_token
to their requests. Curity has introspection endpoint which we can use to verify the token and get the information related to the token.
1 | curl --request POST \ |
Authorization code
Users need to use a browser for this flow. Please copy below URL to notepad, change domain
, client_id
, redirect_uri
to match your settings. Once we open this link on browser, we should be redirected to a log in page. Please enter username and password to log in.
1 | https://curity.yourdomain.com/oauth/v2/oauth-authorize?client_id=demo-client&response_type=code&redirect_uri=https://localhost/callback&scope=openid |
We will be redirected back to https://localhost/callback
, the URL should look like below.
1 | https://localhost/callback?code=FJkRwmV6l9cEQZ0jAvy61uSeUQozLdE6&session_state=iInaq3R3hDkdfR3AbrXk1T7tbLPLRw%2BgOXu8qlvrH8A%3D.1oh0CU0HPUsw |
FJkRwmV6l9cEQZ0jAvy61uSeUQozLdE6
is the code we need to redeem our tokens.
1 | curl --request POST \ |
Now we should get id_token
, access_token
and refresh_token
.
That’s all I want to show you in this post.
My plan is to cover more IDPs in future. Started from the self-hosted ones first and then move on to cloud IDPs like Okta, Azure AD or Auth0. Although you don’t need to worry about deployment for those IDPs, they have their own challenges when you try to use it to suit your needs. If you want me to cover on cloud IDPs, please leave your comment.
That’s all for today, see you next time.