# Proof of concept OpenID Connect / OAuth server with ORY Hydra **The work on this project continues at https://code.cacert.org/cacert/oidc-parent and repositories referenced there.** This repository contains a proof of concept implementation for an identity provider and an application using OIDC. [ORY Hydra](https://www.ory.sh/hydra/) is used for the actual OAuth2 / OpenID Connect operations. The implementation in this repository provides the UI components that are required by Hydra. The code in this repository is licensed under the terms of the Apache License Version 2.0. Copyright © 2020, 2021 Jan Dittberner ## Setup ### Certificates You need a set of certificates for the IDP, the application and Hydra. You can use the Test CA created by the ``setup_test_ca.sh`` script from the [CAcert developer setup](https://git.dittberner.info/jan/cacert-devsetup) repository like this: 1. create signing requests ``` mkdir certs cd certs openssl req -new -newkey rsa:3072 -nodes \ -keyout hydra.cacert.localhost.key \ -out hydra.cacert.localhost.csr.pem \ -subj /CN=hydra.cacert.localhost \ -addext subjectAltName=DNS:hydra.cacert.localhost,DNS:auth.cacert.localhost openssl req -new -newkey rsa:3072 -nodes \ -keyout idp.cacert.localhost.key \ -out idp.cacert.localhost.csr.pem \ -subj /CN=idp.cacert.localhost \ -addext subjectAltName=DNS:idp.cacert.localhost,DNS:login.cacert.localhost,DNS:register.cacert.localhost openssl req -new -newkey rsa:3072 -nodes \ -keyout app.cacert.localhost.key \ -out app.cacert.localhost.csr.pem \ -subj /CN=app.cacert.localhost \ -addext subjectAltName=DNS:app.cacert.localhost cp *.csr.pem $PATH_TO_DEVSETUP_TESTCA/ ``` 2. Use the CA to sign the certificates ``` pushd $PATH_TO_DEVSETUP_TESTCA/ for csr in hydra idp app; do openssl ca -config ca.cnf -name class3_ca -extensions server_ext \ -in ${csr}.cacert.localhost.csr.pem \ -out ${csr}.cacert.localhost.crt.pem -days 365 done popd cp $PATH_TO_DEVSETUP_TESTCA/{hydra,idp,app}.cacert.localhost.crt.pem . ``` 3. Copy CA certificate for client certificates ``` openssl x509 -in $PATH_TO_DEVSETUP_TESTCA/class3/ca.crt.pem \ -out client_ca.pem ``` ### Setup Hydra We use the ORY Hydra OAuth2 / OpenID Connect implementation. Install Hydra according to their [documentation](https://www.ory.sh/hydra/docs/install). The setup has been tested with the Linux binary installation. Perform the Hydra database setup: ``` sudo -i -u postgres psql > CREATE DATABASE hydra_local ENCODING utf-8; > CREATE USER hydra_local WITH PASSWORD '${YOUR_POSTGRESQL_PASSWORD}'; > GRANT CONNECT, CREATE ON DATABASE hydra_local TO hydra_local; hydra migrate sql "postgres://hydra_local:${YOUR_POSTGRESQL_PASSWORD}@localhost:5432/hydra_local" ``` Create a configuration file for Hydra i.e. ``hydra.yaml``: ``` serve: admin: host: hydra.cacert.localhost public: host: auth.cacert.localhost tls: cert: path: certs/hydra.cacert.localhost.crt.pem key: path: certs/hydra.cacert.localhost.key dsn: 'postgres://hydra_local:${YOUR_POSTGRESQL_PASSWORD}@localhost:5432/hydra_local' webfinger: oidc_discovery: supported_claims: - email - email_verified - given_name - family_name - middle_name - name - birthdate - zoneinfo - locale - https://cacert.localhost/groups supported_scope: - profile - email oauth2: expose_internal_errors: false urls: login: https://login.cacert.localhost:3000/login consent: https://login.cacert.localhost:3000/consent logout: https://login.cacert.localhost:3000/logout error: https://login.cacert.localhost:3000/error post_logout_redirect: https://login.cacert.localhost:3000/logout-successful self: public: https://auth.cacert.localhost:4444/ issuer: https://auth.cacert.localhost:4444/ secrets: system: - "${YOUR SECRET FOR HYDRA}" ``` The available configuration options are described in the [Hydra configuration documentation](https://www.ory.sh/hydra/docs/reference/configuration). Hydra needs to be able to resolve its hostnames and does not work with the systemd-nss module. You therefore need to define Hydra's hostnames in your ``/etc/hosts`` file: ``` ::1 auth.cacert.localhost hydra.cacert.localhost ``` ### Add OpenID Connect configuration for a client Create an OpenID Connect (OIDC) client configuration for the demo application ``` hydra clients create --endpoint https://hydra.cacert.localhost:4445/ \ --callbacks https://app.cacert.localhost:4000/callback \ --logo-uri https://register.cacert.localhost:3000/images/app.png \ --name "Client App Demo" \ --scope "openid offline_access profile email" \ --post-logout-callbacks https://app.cacert.localhost:4000/after-logout \ --client-uri https://register.cacert.localhost:3000/info/app ``` The command returns a client id and a client secret, that you need for the demo application configuration. ### Configure IDP The Identity Provider application (IDP) requires a strong random key for its CSRF cookie. You can generate such a key using the following openssl command: ``` openssl rand -base64 32 ``` Use this value and the database credentials from your cacert-devsetup and create `idp.toml`: ``` [security] csrf.key = "<32 bytes of base64 encoded data>" [db] dsn = "$MYSQL_USER:$MYSQL_PASSWORD@tcp(localhost:13306)/cacert ``` ### Configure the Demo Application You will need a 32 byte and a 64 byte random secret for the session authentication and encryption keys: ``` openssl rand -base64 64 openssl rand -base64 32 ``` You also need the client id and the client secret, that have been generated during the OIDC client setup described above. ``` [oidc] client-id = "" client-secret = "" [session] auth-key = "<64 bytes of base64 encoded data>" enc-key = "<32 bytes of base64 encoded data>" ``` ## Frontend resource build The frontend resources are built using [webpack 5](https://webpack.js.org/) and [yarn](https://classic.yarnpkg.com/lang/en/). You need recent nodejs and yarn versions. See the [Debian installation instructions](https://github.com/nodesource/distributions/blob/master/README.md#debinstall) of nodesource or look at the other options on the [nodejs Download page](https://nodejs.org/en/download/) if you cannot use Debian Bullseye or newer. When you are sure that you have nodejs >= 12 and yarn you can install the required dependencies and run webpack like this: ``` yarn yarn run build ``` ## Start Now you can start Hydra, the IDP and the demo app in 3 terminal windows: ``` hydra serve all --config hydra.yaml ``` ``` go run cmd/idp/main.go ``` ``` go run cmd/app/main.go ``` Visit https://app.cacert.localhost:4000/ in a Browser and you will be directed through the OpenID connect authorization code flow. ## Translations This application uses [go-i18n](https://github.com/nicksnyder/go-i18n/) for internationalization (i18n) support. The translation workflow needs the `go18n` binary which can be installed via ``` go get -u github.com/nicksnyder/go-i18n/v2/goi18n ``` To extract new messages from the code run ``` goi18n extract . ``` Then use ``` goi18n merge active.*.toml ``` to create TOML files for translation as `translate..toml`. After translating the messages run ``` goi18n merge active.*.toml translate.*.toml ``` to merge the messages back into the active translation files. To add a new language you need to add the language code to the languages configuration option (default is defined in the configmap in cmd/idp/main.go and cmd/app/main.go).