×
Community Blog API Gateway OpenID Connect Practice: SSO Made Simple

API Gateway OpenID Connect Practice: SSO Made Simple

This article introduces the open source OIDC Wasm plugin in Higress through specific step-by-step examples, helping users achieve SSO (Single Sign-On) without writing any code.

By Jingze Dai, Developer of Alibaba Cloud API Gateway, Member of the Higress Open Source Community

1. Introduction

As businesses grow, the number of systems they use also increases, leading to a poor user experience due to the need for frequent logins across different systems. Single Sign-On (SSO) is designed to address this issue. SSO allows a single login to grant access to all systems, eliminating the need for individual logins for each system.

Currently, common SSO implementation approaches include:

  1. JWT-based: JWT (JSON Web Token) is an open standard for securely transmitting information between parties, containing user identity and permissions. However, when used for SSO, JWT lacks a standardized approach, making integration complex. In addition, once issued, tokens cannot be revoked, which may affect security.
  2. CAS-based: CAS (Central Authentication Service) is an open source SSO solution based on middleware, commonly used in universities and large enterprises. Once logged in, users can seamlessly access all CAS-integrated applications. However, its implementation is relatively complex and requires high system integration.
  3. SAML-based: SAML (Security Assertion Markup Language) is a protocol for exchanging authentication information between applications and SSO services. It uses XML to exchange user identification data, offering high security and flexibility, but its configuration and deployment are complex, increasing development and maintenance costs.
  4. OIDC-based: OIDC (OpenID Connect) is an authentication layer built on top of OAuth 2.0, allowing users to authenticate through various clients such as web and mobile applications. OIDC offers standardization, ease of use, flexibility, and security, making it the preferred choice for many enterprises implementing SSO.

OIDC is also widely supported by third-party service providers like Alipay, DingTalk, WeChat, GitHub, and more. For example, the login page of the Sealos application allows third-party logins via GitHub, WeChat, and Google, using OIDC for authentication.

1

The Higress gateway, which is the entry point for all requests to backend services, can integrate with OIDC to provide a unified authentication service. This means that backend services do not need to implement their own user authentication logic; instead, user identity authentication is handled centrally through the gateway. This simplifies the system architecture, reduces redundant work, and improves security.

Users can configure OIDC authentication at the gateway to achieve fine-grained access control over resources. It also facilitates easy integration with self-managed identity authentication services or other third-party accounts, such as social media, improving business convenience.

Based on this, we developed an OIDC plugin that allows users to implement SSO in the Higress gateway without writing any code.

2. OIDC Plugin Usage

2.1 Backend Sample Service Deployment

Deploy a backend sample service in the cluster, such as the Istio Bookinfo example, for testing the OIDC plugin functionality. After deployment, you can use the following command to verify if the deployment is successful.

kubectl exec "$(kubectl get pod -l app=ratings -o jsonpath='{.items[0].metadata.name}')" -c ratings -- curl -sS productpage:9080/productpage | grep -o "<title>.*</title>"

2.2 Use the OIDC Plugin with a Self-managed Identity Service

Examples:

Deploy the keycloak authentication service

Quickly deploy the keycloak authentication service using Docker by following the keycloak-getting-started-docker guide. Add a user and create a client.

Note: You need to fill in the Valid redirect URIs, Valid post logout URIs, and Web origins configuration options; otherwise, the OIDC Provider will consider the user's redirect or logout URLs invalid.

Higress service configuration

Create a keycloak fixed address service in the Higress service sources.

2

Wasm plugin configuration

redirect_url: 'http://foo.bar.com/oauth2/callback'
oidc_issuer_url: 'http://127.0.0.1:9090/realms/myrealm'
client_id: 'XXXXXXXXXXXXXXXX'
client_secret: 'XXXXXXXXXXXXXXXX'
scope: 'openid email'
cookie_secret: 'nqavJrGvRmQxWwGNptLdyUVKcBNZ2b18Guc1n_8DCfY='
service_name: 'keycloak.static'
service_port: 80
service_host: '127.0.0.1:9090'

Plugin Effect Demonstration

Access the service page, and if you are not logged in, it will redirect to the login page.

3

After a successful login, it will redirect back to the service page.

4

Accessing the logout will redirect to the logout page.

http://foo.bar.com/oauth2/sign_out?rd=http%3A%2F%2F127.0.0.1:9090%2Frealms%2Fmyrealm%2Fprotocol%2Fopenid-connect%2Flogout

5

Accessing the logout will redirect to the logout page (with the post_logout_redirect_uri parameter to redirect to a specified URI).

http://foo.bar.com/oauth2/sign_out?rd=http%3A%2F%2F127.0.0.1:9090%2Frealms%2Fmyrealm%2Fprotocol%2Fopenid-connect%2Flogout%3Fpost_logout_redirect_uri%3Dhttp%3A%2F%2Ffoo.bar.com%2Ffoo

2.3 Use the OIDC Plugin through a Third-party Service Provider

Example:

Configure Alibaba Cloud OAuth applications

Follow the process outlined in Access Alibaba Cloud APIs from a web application to configure the OAuth application.

Higress service configuration

To allow the plugin to access the OIDC service provider, create an Aliyun DNS service in the Higress service sources.

6

Plugin parameter configuration

redirect_url: 'http://foo.bar.com/oauth2/callback'
provider: aliyun
oidc_issuer_url: 'https://oauth.aliyun.com/'
client_id: 'XXXXXXXXXXXXXXXX'
client_secret: 'XXXXXXXXXXXXXXXX'
scope: 'openid'
cookie_secret: 'nqavJrGvRmQxWwGNptLdyUVKcBNZ2b18Guc1n_8DCfY='
service_name: 'aliyun.dns'
service_port: 443

Plugin Effect Demonstration

Access the service page, and if you are not logged in, it will redirect to the login page.

7

Scanning the QR code for login will redirect to the service page upon successful authentication.

8

Accessing the logout will redirect to the logout page (after logging out from Alibaba Cloud, it will redirect to the login page).

http://foo.bar.com/oauth2/sign_out?rd=https%3A%2F%2Faccount.aliyun.com%2Flogout%2Flogout.htm

3. OIDC Plugin Solution Selection

3.1 Istio Sidecar Container Solution

The Istio community has proposed using a Sidecar container for external authorization, such as the mature oauth2-proxy solution mentioned in Istio OIDC Authentication with OAuth2-Proxy. However, this solution has some drawbacks. Firstly, it adds an extra layer of request calls between the external authorization service and the data plane, which can lead to performance degradation. Secondly, the external authorization service consumes CPU and memory resources. Additionally, if users need to configure multiple service providers, they would have to deploy multiple external authorizations, making this solution less flexible.

3.2 Envoy Filter Solution

The existing C++ native OAuth2 Filter developed by the Envoy community can also implement OIDC authentication. The Envoy community's envoy gateway project uses this solution, which is currently under active development. However, there are issues: it does not support the standard OIDC protocol state parameter (Issue 35232), making it vulnerable to CSRF attacks, and it does not support encrypting tokens in cookies (Issue 23508). These security vulnerabilities make the OAuth2 Filter unsuitable for production use.

3.3 Wasm Plugin Solution

The open source Higress project plugin development framework supports writing Wasm plugins in various programming languages, including Rust, C++, Golang, and AssemblyScript (a Wasm dialect of TypeScript). Compared with the C++ ecosystem, languages like Rust, Go, and TypeScript have a richer set of open source libraries. Some open source projects that implement OIDC functionality include:

Golang: oauth2-proxy

Rust: oauth2-rs

TypeScript: angular-oauth2-oidc

Among these, the oauth2-proxy project is widely used and validated in the open source community, with the most active community support and frequent updates and improvements. It implements most of the common OIDC service providers and is recommended in the Istio Sidecar container solution. The advantages of the Wasm plugin solution are as follows:

  1. Production availability: Since the OIDC protocol involves authentication, its stability and security are critical. Plugins with custom development based on mature open source projects typically offer higher reliability.
  2. Scalability: When different enterprises implement the OIDC protocol, they may not fully adhere to the standard. Enterprise users can customize the plugin based on open source code to meet their specific needs.
  3. Security: The plugins run in a strictly sandboxed virtual environment, so even if the code has issues, it will not cause Envoy to crash.

Given these advantages and considering the flexibility and security issues of the first two solutions, the Wasm plugin solution was developed to implement OIDC functionality.

4. OIDC Plugin Principle

The OIDC plugin is based on the core process of the oauth2-proxy project. Since initiating external requests in Envoy plugins requires asynchronous calls, the synchronous calls in the main flow of the oauth2-proxy project have been modified to asynchronous calls with external services in Envoy. The response is then processed in a callback function. For specific code, refer to the OIDC plugin in Higress. The request response flow of the OIDC plugin is as follows:

9

1.  Simulate a user to access the corresponding service APIs.

curl --url "foo.bar.com/headers"

2.  Higress redirects to the OIDC Provider's login page with OIDC authentication parameters such as client_id, response_type, and scope, and sets a CSRF cookie to defend against CSRF attacks.

curl --url "https://dev-o43xb1mz7ya7ach4.us.auth0.com/authorize"\
  --url-query "approval_prompt=force" \
  --url-query "client_id=YagFqRD9tfNIaac5BamjhsSatjrAnsnZ" \
  --url-query "redirect_uri=http%3A%2F%2Ffoo.bar.com%2Foauth2%2Fcallback" \
  --url-query "response_type=code" \
  --url-query "scope=openid+email+offline_access" \
  --url-query "state=nT06xdCqn4IqemzBRV5hmO73U_hCjskrH_VupPqdcdw%3A%2Ffoo" \
  --header "Set-Cookie: _oauth2_proxy_csrf=LPruATEDgcdmelr8zScD_ObhsbP4zSzvcgmPlcNDcJpFJ0OvhxP2hFotsU-kZnYxd5KsIjzeIXGTOjf8TKcbTHbDIt-aQoZORXI_0id3qeY0Jt78223DPeJ1xBqa8VO0UiEOUFOR53FGxirJOdKFxaAvxDFb1Ok=|1718962455|V1QGWyjQ4hMNOQ4Jtf17HeQJdVqHdt5d65uraFduMIU=; Path=/; Expires=Fri, 21 Jun 2024 08:06:20 GMT; HttpOnly"

3.  The user logs in on the login page.

10

4.  The user is redirected back to Higress with an authorization code and a state parameter to validate the CSRF cookie. The authorization code is used to exchange for a token.

curl --url "http://foo.bar.com/oauth2/callback" \
  --url-query "state=nT06xdCqn4IqemzBRV5hmO73U_hCjskrH_VupPqdcdw%3A%2Ffoo" \
  --url-query "code=0bdopoS2c2lx95u7iO0OH9kY1TvaEdJHo4lB6CT2_qVFm"

5.  The authorization code is used to exchange for id_token and access_token.

curl -X POST \
  --url "https://dev-o43xb1mz7ya7ach4.us.auth0.com/oauth/token" \
  --data "grant_type=authorization_code" \
  --data "client_id=YagFqRD9tfNIaac5BamjhsSatjrAnsnZ" \
  --data "client_secret=ekqv5XoZuMFtYms1NszEqRx03qct6BPvGeJUeptNG4y09PrY16BKT9IWezTrrhJJ" \
  --data "redirect_uri=http%3A%2F%2Ffoo.bar.com%2Foauth2%2Fcallback" \
  --data "code=0bdopoS2c2lx95u7iO0OH9kY1TvaEdJHo4lB6CT2_qVFm" \

The returned request includes the id_token, access_token, and refresh_token for future access_token refreshes.

{
    "access_token": "eyJhbGciOiJkaXIiLCJlbmMiOiJBMjU2R0NNIiwiaXNzIjoiaHR0cHM6Ly9kZXYtbzQzeGIxbXo3eWE3YWNoNC51cy5hdXRoMC5jb20vIn0..WP_WRVM-y3fM1sN4.fAQqtKoKZNG9Wj0OhtrMgtsjTJ2J72M2klDRd9SvUKGbiYsZNPmIl_qJUf81D3VIjD59o9xrOOJIzXTgsfFVA2x15g-jBlNh68N7dyhXu9237Tbplweu1jA25IZDSnjitQ3pbf7xJVIfPnWcrzl6uT8G1EP-omFcl6AQprV2FoKFMCGFCgeafuttppKe1a8mpJDj7AFLPs-344tT9mvCWmI4DuoLFh0PiqMMJBByoijRSxcSdXLPxZng84j8JVF7H6mFa-dj-icP-KLy6yvzEaRKz_uwBzQCzgYK434LIpqw_PRuN3ClEsenwRgIsNdVjvKcoAysfoZhmRy9BQaE0I7qTohSBFNX6A.mgGGeeWgugfXcUcsX4T5dQ",
    "refresh_token": "GrZ1f2JvzjAZQzSXmyr1ScWbv8aMFBvzAXHBUSiILcDEG",
    "id_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6Imc1Z1ExSF9ZbTY0WUlvVkQwSVpXTCJ9.eyJlbWFpbCI6IjE2MDExNTYyNjhAcXEuY29tIiwiZW1haWxfdmVyaWZpZWQiOmZhbHNlLCJpc3MiOiJodHRwczovL2Rldi1vNDN4YjFtejd5YTdhY2g0LnVzLmF1dGgwLmNvbS8iLCJhdWQiOiJZYWdGcVJEOXRmTklhYWM1QmFtamhzU2F0anJBbnNuWiIsImlhdCI6MTcxOTE5ODYzOCwiZXhwIjoxNzE5MjM0NjM4LCJzdWIiOiJhdXRoMHw2NjVkNzFlNzRjMTMxMTc3YmU2NmU2MDciLCJzaWQiOiJjdDJVOF9ZUS16VDdFOGkwRTNNeUstejc5ZGlWUWhhVSJ9.gfzXKJ0FeqzYqOUDLQHWcUG19IOLqkpLN09xTmIat0umrlGV5VNSumgWH3XJmmwnhdb8AThH3Jf-7kbRJzu4rM-BbGbFTRBTzNHeUajFOFrIgld5VENQ_M_sXHkTp0psWKSr9vF24kmilCfSbvC5lBKjt878ljZ7-xteWuaUYOMUdcJb4DSv0-zjX01sonJxYamTlhji3M4TAW7VwhwqyZt8dBhVSNaRw1wUKj-M1JrBDLyx65sroZtSqVA0udIrqMHEbWYb2de7JjzlqG003HRMzwOm7OXgEd5ZVFqgmBLosgixOU5DJ4A26nlqK92Sp6VqDMRvA-3ym8W_m-wJ_A",
    "scope": "openid email offline_access",
    "expires_in": 86400,
    "token_type": "Bearer"
}

6.  The obtained id_token and access_token are encrypted and stored in the Cookie _oauth2_proxy for subsequent user login state validation. The Cookie _oauth2_proxy_csrf is cleared.

"Set-Cookie": [
    "_oauth2_proxy_csrf=; Path=/; Expires=Mon, 24 Jun 2024 02:17:39 GMT; HttpOnly",
    "_oauth2_proxy=8zM_Pcfpp_gesKFe4SMg08o5Iv0A8WAOQOmG1-vZBbQ56UggYVC0Cu-gFMEoxJZU5q1O5vqRlVBizlLetgVjRCksGVbttwl8tQ7h5YiyIubbbtvF1T4JzLh3QfzUUrwbB-VznOkh8qLbjAhddocecjBt4rMiDyceKXqMr4eO5TUEMx4vHtJYnTYalMeTYhGXk5MNSyrdZX9NnQnkdrCjiOQM13ggwob2nYwhGWaAlgzFSWkgkdtBy2Cl_YMWZ8_gKk9rDX289-JrJyGpr5k9O9RzRhZoY2iE3Mcr8-Q37RTji1Ga22QO-XkAcSaGqY1Qo7jLdmgZTYKC5JvtdLc4rj3vcbveYxU7R3Pt2vEribQjKTh4Sqb0aA03p4cxXyZN4SUfBW1NAOm4JLPUhKJy8frqC9_E0nVqPvpvnacaoQs8WkX2zp75xHoMa3SD6KZhQ5JUiPEiNkOaUsyafLvht6lLkNDhgzW3BP2czoe0DCDBLnsot0jH-qQpMZYkaGr-ZnRKI1OPl1vHls3mao5juOAW1VB2A9aughgc8SJ55IFZpMfFMdHdTDdMqPODkItX2PK44GX-pHeLxkOqrzp3GHtMInpL5QIQlTuux3erm3CG-ntlUE7JBtN2T9LEb8XfIFu58X9_vzMun4JQlje2Thi9_taI_z1DSaTtvNNb54wJfSPwYCCl4OsH-BacVmPQhH6TTZ6gP2Qsm5TR2o1U2D9fuVkSM-OPCG9l3tILambIQwC3vofMW6X8SIFSmhJUDvN7NbwxowBiZ6Y7GJRZlAk_GKDkpsdrdIvC67QqczZFphRVnm6qi-gPO41APCbcO6fgTwyOhbP3RrZZKWSIqWJYhNE3_Sfkf0565H7sC7Hc8XUUjJvP3WnjKS9x7KwzWa-dsUjV3-Q-VNl-rXTguVNAIirYK-qrMNMZGCRcJqcLnUF0V_J2lVmFyVsSlE3t0sDw2xmbkOwDptXFOjQL5Rb4esUMYdCBWFajBfvUtcZEFtYhD0kb6VcbjXO3NCVW5qKh_l9C9SRCc7TG1vcRAqUQlRXHacTGWfcWsuQkCJ3Mp_oWaDxs1GRDykQYxAn5sTICovThWEU2C6o75grWaNrkj5NU-0eHh3ryvxLmGLBOXZV9OQhtKShWmUgywSWMxOHOuZAqdAPULc8KheuGFjXYp-RnCbFYWePJmwzfQw89kSkj1KUZgMYwKEjSz62z2qc9KLczomv76ortQzvo4Hv9kaW6xVuQj5R5Oq6_WMBOqsmUMzcXpxCIOGjcdcZRBc0Fm09Uy9oV1PRqvAE4PGtfyrCaoqILBix8UIww63B07YGwzQ-hAXDysBK-Vca2x7GmGdXsNXXcTgu00bdsjtHZPDBBWGfL3g_rMAXr2vWyvK4CwNjcaPAmrlF3geHPwbIePT0hskBboX1v1bsuhzsai7rGM4r53pnb1ZEoTQDa1B-HyokFgo14XiwME0zE1ifpNzefjpkz1YY2krJlqfCydNwoKaTit4tD2yHlnxAeFF9iIrxzSKErNUFpmyLa7ge7V33vhEH-6k5oBTLE2Q2BrC6aAkLCcPwU9xv_SzBDQPRY0MEYv3kGF03Swo1crRbGh-aifYX9NiHDsmG6r1vAnx0MAOw2Jzuz2x6SSdfBrzlcoWBlrwiZzd9kAKq75n1Uy9uzZ8SRnkBrEZySHBwEbu196VklkRE0jqwC-e3wWNNuviSOfwkVeX-7QdOoO10yw9VK2sW52lFvIEf4chv_ta7bGfAZOWBjpktG6ZLD81SE6A88zpqG2SysSyNMp9hl-umG-5sFsjCn_c9E8bDvwkUOUVb9bNqhBDsZgR0BNPawiOZjmyfhzmwmWf-zgFzfFSV6BvOwNRi3sCOHTsWcuk9NBQ_YK8CpNkVl3WeIBSDfidimuC_QV9UWKs1GPk35ZRkM4zKtLY2JsBFWKaDy_P80TcOzcMBoP8gIBClXZ-WUqfE8s1yyc4jrq-qL1_wJ24ef1O9FktsbyZiDKXw2vnqsT8-g_hCeG-unrT1ZFscf8oNdqczARHX-K4vKH2k3uIqEx1M=|1719199056|2rsgdUIClHNEpxBLlHOVRYup6e4oKensQfljtmn4B80=; Path=/; Expires=Mon, 01 Jul 2024 03:17:36 GMT; HttpOnly"
]

7.  The API is accessed with an Authorization header containing the access_token.

curl --url "foo.bar.com/headers"
--header "Authorization: Bearer eyJhbGciOiJkaXIiLCJlbmMiOiJBMjU2R0NNIiwiaXNzIjoiaHR0cHM6Ly9kZXYtbzQzeGIxbXo3eWE3YWNoNC51cy5hdXRoMC5jb20vIn0..WP_WRVM-y3fM1sN4.fAQqtKoKZNG9Wj0OhtrMgtsjTJ2J72M2klDRd9SvUKGbiYsZNPmIl_qJUf81D3VIjD59o9xrOOJIzXTgsfFVA2x15g-jBlNh68N7dyhXu9237Tbplweu1jA25IZDSnjitQ3pbf7xJVIfPnWcrzl6uT8G1EP-omFcl6AQprV2FoKFMCGFCgeafuttppKe1a8mpJDj7AFLPs-344tT9mvCWmI4DuoLFh0PiqMMJBByoijRSxcSdXLPxZng84j8JVF7H6mFa-dj-icP-KLy6yvzEaRKz_uwBzQCzgYK434LIpqw_PRuN3ClEsenwRgIsNdVjvKcoAysfoZhmRy9BQaE0I7qTohSBFNX6A.mgGGeeWgugfXcUcsX4T5dQ"

8.  The backend service retrieves user information based on the access_token and returns the corresponding HTTP response.

{
    "email": "******",
    "email_verified": false,
    "iss": "https://dev-o43xb1mz7ya7ach4.us.auth0.com/",
    "aud": "YagFqRD9tfNIaac5BamjhsSatjrAnsnZ",
    "iat": 1719198638,
    "exp": 1719234638,
    "sub": "auth0|665d71e74c131177be66e607",
    "sid": "ct2U8_YQ-zT7E8i0E3MyK-z79diVQhaU"
}

5. Summary

This article introduces the open source OIDC Wasm plugin in Higress. Currently, the Wasm plugin in the Higress project supports development in Go, C++, Rust, and AssemblyScript, and more languages will be supported in the future, lowering the threshold for development. Additionally, the Wasm plugin runs in an isolated sandboxed environment, providing higher security. Wasm itself, as a high-performance portable binary instruction format, continues to see new advancements and technological innovations. More features for gateway scenarios can be considered for implementation within Wasm plugins in the future.

The OIDC Wasm plugin described in this article is now available in the Higress project.

0 1 0
Share on

You may also like

Comments