OIDC中JWK,JWKS的介绍与使用

JWKS全称为 JSON Web Key Set,是指多个JWK组合在一起的一种格式(详见 https://tools.ietf.org/html/draft-ietf-jose-json-web-key-41#section-5 );

JWK全称是JSON Web Key,其标准协议链接:https://tools.ietf.org/html/draft-ietf-jose-json-web-key-41

JWK在OIDC中的主要作用是为JWT(id_token)提供加密密钥,用于加密/解密或签名/验签,是JSON格式的数据。

综上所说,掌握了如何生成JWK,再按照JWKS协议的要求组合起来即可。根据使用不同的加密算法,各种算法的JWK展示内容会有些区别,一个使用RSA算法的JWK格式的数据如下,使用jose4j生成:

{
  "kty": "RSA",
  "kid": "myoidc-keyid",
  "use": "sig",
  "alg": "RS256",
  "n": "xMNL1jDatbHWGDH_H9GZbb2R4Ck2ga-lfE6wJnno_MfqJibSqkiLTZ7P06woJFxzB0WDu2PBe-ptRNoJhEnkzL8c1mgbGOdPVCsaaDm-POGZ3gnWGcyzyuJ9s9km41Rlan3TuuC3HIniY4bmyQAZ-SLwrFk7Bfa91ui4F9S5RvM",
  "e": "AQAB",
  "d": "q73XDM65p8vgll_VUn2NUPcdQ65VUB7y76xzHjJchX8tRj2utUj6pjaPKi_jHdG_6UHouIBa2oEE_QrfMaOZ2wA6LgYPXT_a296LKoOtKKRUlgob_leHxn0FJxLOXtEHgMqDgtMQ1-eFipsFgriip94dmcLEWW3YVK_y5JwJrnE",
  "p": "7OqN19bEbMb9cr9zA98QQq9LOgvQfq5-nOvzwMsubqMosHxViRnivFz2-3LpusK7u2XEG5EljqUxZrf4lgeVmw",
  "q": "1Jy9ksoLuQ5tuc4docgLaXQWqf3iaTm3iC07AA4v9jHzvnkewWFS_PUPPcra4475Dew-y7oIENaRBMijrrWViQ",
  "dp": "HBEdhLh4xLo-RF3R7l96uauyqcnEhX1-mnCJjAmGEq1ZoK7aI0fhyJbq25cdgXaYbvb7aJilbmS7mYOp-3wiiQ",
  "dq": "NRMLn-EgHAomCgQSEZjGgISiQ71FD8-AqVXhLJpeDq9ZkWra6ptJBCyIqXxCOBwwv_EBnAnMiaeGfBM6CRr7QQ",
  "qi": "VCdAeu4h25X_kM69Netc3SKPo5P-1VjeSHz0Ko0QuSMF0INc6H2yi7hZgZuYANVaTF1Ipf6lWfHBLpuRGh3lXw"
}

JWK数据的格式具体可参见 https://tools.ietf.org/html/draft-ietf-jose-json-web-key-41#section-4

主要属性:kty(Key类型),use(两个可选值:sig or enc),alg(具体的算法),kid(Key的唯一标识id)

 

有了JWK数据,只需要按照JWKS的格式组装成对应的JSON数据即可,以上面的JWK组装的JWKS数据如下:

{
  "keys": [
    {
      "p": "7OqN19bEbMb9cr9zA98QQq9LOgvQfq5-nOvzwMsubqMosHxViRnivFz2-3LpusK7u2XEG5EljqUxZrf4lgeVmw",
      "kty": "RSA",
      "q": "1Jy9ksoLuQ5tuc4docgLaXQWqf3iaTm3iC07AA4v9jHzvnkewWFS_PUPPcra4475Dew-y7oIENaRBMijrrWViQ",
      "d": "q73XDM65p8vgll_VUn2NUPcdQ65VUB7y76xzHjJchX8tRj2utUj6pjaPKi_jHdG_6UHouIBa2oEE_QrfMaOZ2wA6LgYPXT_a296LKoOtKKRUlgob_leHxn0FJxLOXtEHgMqDgtMQ1-eFipsFgriip94dmcLEWW3YVK_y5JwJrnE",
      "e": "AQAB",
      "use": "sig",
      "kid": "myoidc-keyid",
      "qi": "VCdAeu4h25X_kM69Netc3SKPo5P-1VjeSHz0Ko0QuSMF0INc6H2yi7hZgZuYANVaTF1Ipf6lWfHBLpuRGh3lXw",
      "dp": "HBEdhLh4xLo-RF3R7l96uauyqcnEhX1-mnCJjAmGEq1ZoK7aI0fhyJbq25cdgXaYbvb7aJilbmS7mYOp-3wiiQ",
      "alg": "RS256",
      "dq": "NRMLn-EgHAomCgQSEZjGgISiQ71FD8-AqVXhLJpeDq9ZkWra6ptJBCyIqXxCOBwwv_EBnAnMiaeGfBM6CRr7QQ",
      "n": "xMNL1jDatbHWGDH_H9GZbb2R4Ck2ga-lfE6wJnno_MfqJibSqkiLTZ7P06woJFxzB0WDu2PBe-ptRNoJhEnkzL8c1mgbGOdPVCsaaDm-POGZ3gnWGcyzyuJ9s9km41Rlan3TuuC3HIniY4bmyQAZ-SLwrFk7Bfa91ui4F9S5RvM"
    }
  ]
}

以上的JWK,JWKS的示例的完整代码(JAVA实现)可在此查看 https://gitee.com/mkk/MyOIDC/blob/master/myoidc-server/src/test/java/myoidc/server/infrastructure/JWKSTest.java。代码中还包括除RSA外,ECC,OCT的示例实现。

 

JWK本身未定义一种新的加密算法或变种,只是定义一种JSON格式的数据展示(更符合互联网传输),其底层实现依旧依赖PKI体系的技术,如x509,公钥/私钥体系。在其协议介绍中能更好地体现出来。

20200920160628

 

如果是使用非JAVA语言,也可以使用对应的PKI技术生成JWK,如openssl;

一个使用JDK自带的 keytool 工具生成的示例如下:

keytool -genkeypair -alias oidc-demo -validity 180 -keyalg RSA -keypass oidc-demo -keystore oidc-demo.jks -storepass oidc-demo

命令输入后依次填写DN的各类信息,即可生成 oidc-demo.jks文件,密码为 oidc-demo,文件中有私钥公钥等信息。

若需要导出为 x509格式数据,使用keytool命令:

keytool -exportcert -keystore oidc-demo.jks -rfc -file oidc-demo.cer -alias oidc-demo

输入密码后生成的 oidc-demo.cer文件为x509格式。

 

OIDC中的术语介绍与示例

 

以下对OIDC主要的术语进行说明,并与OAuth2作相关对比。

  • EU End-User, 指用户(一般指有账号的个体,资源的拥有者)
  • RP Relying Party, 信任方(一般是一个软件应用), 理解为OAuth2中的客户端(client)即可, 需要在OP中注册
  • OP OpenID Provider, 能提供对EU进行认证的服务端(可理解为OAuth2中授权服务端),
    提供RP的注册(或管理)能力,EU管理,ID Token的签发与管理等。OIDC中的核心组件。
    OIDC-Server 就是一个OP的参考实现
  • ID Token 格式为JSON Web Token(JWT),
    包含EU认证授权信息等. 有关JWT请访问 https://jwt.io/除了JWT, 知道以下概念对掌握OIDC会很有帮助
    JSON Web Key(JWK),
    JSON Web Encryption(JWE),
    JSON Web Algorithm(JWA),
    JSON Web Signature(JWS)
  • UserInfo Endpoint EU信息接口(OAuth2保护), 在RP获取到access_token后,可调用此接口获取EU的详细信息.
    OIDC要求此接口必须使用https访问(更安全);一般在OP中提供的Discovery中获取
  • Claim EU信息的载体, 可在id_token中获取,主要包括认证信息与授权信息,可根据实际扩展
  • 查看完整术语定义请访问 https://openid.net/specs/openid-connect-core-1_0.html#Terminology

OIDC协议中抽象了一个主要的操作步骤与流程示意图,如下:

20200920150958

下面以AWS提供的OIDC服务来举例说明。 假设你现在有一个应用A想集成使用AWS的OIDC服务,在实现OIDC之前需要先做几件事

  1. 应用A(RP)先去AWS(OP)中注册一个应用并获取对应的client_id, client_secret,public key等信息( 一般这步骤是开发者去完成)。注册时一般需要提供应用名称,redirect_uri等信息。
  2. 根据AWS提供的实现文档进行应用A(RP)的集成(也是开发者完成)。

OIDC流程在此示例中的关系图如下:

20200920151748

结束。

 

详细完整的使用请访问 MyOIDC: https://gitee.com/mkk/MyOIDC

 

MyOIDC v1.1.1 发布,基于 OIDC 协议的参考实现,根据各类库提供实现参考

MyOIDC  –基于OIDC协议的参考实现,根据各类库提供实现参考 。正式版本v1.1.1发布,主要更新内容:

  1. 修改启动方法为jar直接运行
  2. 更新How-To-Use.txt
  3. AccessToken使用时允许获取更详细用户信息
  4. 增加 JWKS test与使用说明示例
  5. jose4j升级使用0.7.1版本

openid

GitHub:   https://github.com/monkeyk/MyOIDC/tree/v1.1.1

Gitee:  https://gitee.com/mkk/MyOIDC/tree/v1.1.1

MyOIDC v1.1.0 发布–基于OIDC协议的参考实现,根据各类库提供实现参考

MyOIDC  –基于OIDC协议的参考实现,根据各类库提供实现参考 。第1个正式版本v1.1.0发布,主要更新内容:

  1. 实现OIDC协议的主要流程,包括 DiscoveryEndpoint等各类Endpoint提供实现参考;实现OIDC中主要的认证授权流程;JWKS API实现等。
  2. 实现myoidc-server, myoidc-client 两模块的各类功能细节,能实际使用,形成操作闭环。
  3. openid

V1.1.0 代码库链接:

GitHub:  https://github.com/monkeyk/MyOIDC/tree/v1.1.0

Gitee: https://gitee.com/mkk/MyOIDC/tree/v1.1.0/

 

MyOIDC – 基于OIDC协议的开源项目

在之前的博客文章中, 曾不止一次介绍了OIDC协议及相关知识(详细访问: https://andaily.com/blog/?s=OIDC)

现在,开始一个新的开源项目: MyOIDC (https://git.oschina.net/mkk/MyOIDC), 将其相关的知识与实现给代码化,

我们将着重提供比OAuth2实现更好,更安全的认证与授权 安全框架实现.

 

顺便传播OIDC, 使用OIDC, 拥抱OIDC…

欢迎你的关注与支持…

 

https://git.oschina.net/mkk/MyOIDC

openid

OIDC(OpenID-Connect) 1.0 协议中文版

OIDC(OpenID-Connect) 1.0协议的最终版本早已确认, 用自己的语言在进行翻译中(core部分),

OpenID Connect Core 1.0 incorporating errata set 1

 

截止2016-08-28的翻译进度(章节3.1.2.3)

中文版: https://monkeyk.com/oidc/Final_OpenID-Connect-Core-1.0-incorporating-errata-set-1_CN.html

英文原版: http://openid.net/specs/openid-connect-core-1_0.html

 

JSON Web Signature(JWS): https://tools.ietf.org/html/rfc7515

 

对应的开源项目地址: http://git.oschina.net/shengzhao/spring-oauth-server/tree/master/others/oidc?dir=1&filepath=others%2Foidc&oid=ec2b907c58efcb56a8c774e8f7868ab80c6cb69a&sha=25a0e1f2357768eadf3f0e3b8035959e3bbd3d66http://git.oschina.net/shengzhao/spring-oauth-server/tree/master/others/oidc?dir=1&filepath=others%2Foidc&oid=ec2b907c58efcb56a8c774e8f7868ab80c6cb69a&sha=25a0e1f2357768eadf3f0e3b8035959e3bbd3d66

持续更新中…

 

也可访问: http://www.cnblogs.com/linianhui/p/openid-connect-core.html

 

与OIDC相关介绍请访问: https://andaily.com/blog/?p=440

OIDC–基于OAuth2的下一代身份认证授权协议

OIDC(OpenID Connect), 下一代的身份认证授权协议; 当前发布版本1.0;

OIDC是基于OAuth2+OpenID整合的新的认证授权协议; OAuth2是一个授权(authorization)的开放协议, 在全世界得到广泛使用, 但在实际使用中,OAuth2只解决了授权问题, 没有实现认证部分,往往需要添加额外的API来实现认证; 而OpenID呢,是一个认证(authentication )的协议, 二者在实际使用过程中都有其局限性;

综合二者,即是OIDC; 通过OIDC,既能有OAUTH2的功能,也有OpenID的功能; 恰到好处…

OIDC将是替换(或升级)OAuth2, OpenID的不二选择..

OIDC在OAuth2的access_token的基础上增加了身份认证信息; 通过公钥私钥配合校验获取身份等其他信息—– 即idToken;

一个使用JWT生成的idToken(base64):

eyJhbGciOiJSUzI1NiIsImtpZCI6IjM3MTc2NjA0OTExODEyNzkwNzgifQ.eyJpc3MiOiIxMTExIiwiYXVkIjoiMTExMSIsImF0X2hhc2giOiI4ZjgxYThjOS1jNWJiLTQwOWMtYjI0Ni1lMzEyZmUwYzM4NWMiLCJyZWdpc3RyYXRpb24iOiIxMjM0NTY3OCIsImV4cCI6MTQ2MzYyMjA4NiwianRpIjoiRnl5aGZOYnQtU0NLR2tpTWRGMVg2dyIsImlhdCI6MTQ2MzU3ODg4NiwibmJmIjoxNDYzNTc4ODI2LCJzdWIiOiJsc3otb2lkYyJ9.hDCcs8PISdwUPp6Eyd-9JCeeTJ2ZtscBeuPITIt43gMYbddiUBLC90uT9bxKe6e3awHels3asEMreFtlnlY09PwdCxXvhjYcEiXO_dnzqu-zQXESHzPEE6d1WsZUcbj6yxoxMh0laba24uu3CbqSRQbOrsYmh2_XA5Q5eP66iOajRUDhNXhmsWEL85jtL9_h0SyfRNPZ9C0mRu2x9YZTHT129O53ggqtjwQxrXLAbCd1dd35DyIztagqQWDpo3gFG7YseNEiQ6Mf2D6nIBU9llAqH4sTThq_ahME06qKENat_sxnmIJN2UHw7u0E08S-59oxtOY9winT78Qj5IfWJw

 

在OIDC协议的实现中, 其底层是基于OAuth2. 一些常用的库如: JWT(https://jwt.io/), JWS; OAuth2的实现如: Spring Security OAuth, OLTU.

更多信息可参考: http://openid.net/connect/

OIDC 1.0协议: http://openid.net/specs/openid-connect-core-1_0.html

拥抱OIDC…

openid-r-logo-900x360

OAuth2中 access_token,refresh_token的各类配置与使用场景FAQ

过去几年的OAuth2经历与使用,总结一下,记录有关 access_token, refresh_token的各类配置与场景适应,到此以自问自答的形式把这些琐碎的点总结下来。

说明:以下问答中的截图或表等信息以 spring-oauth-server 中配置为参考。

 

> 问:可以设置永不过期的 refresh_token吗?

答:可以,需要按以下步骤操作:首先在client_details定义中不设置 refresh_token_validity 字段值(即默认null),其次在配置OAuth2的DefaultTokenServices时将refreshTokenValiditySeconds属性值配置为0或小于0(默认为30天,若想修改为其他默认值也在此配置),关键代码看下图

111

 

> 问:可以设置永不过期的 access_token吗?

答:可以,但不推荐使用(因为永不过期意味着除手动清除外无安全性可言);若需要按以下步骤操作:首先在client_details定义中不设置 access_token_validity字段值(即默认null),其次在配置OAuth2的DefaultTokenServices时将accessTokenValiditySeconds属性值配置为0或小于0(默认为12小时,若想修改为其他默认值也在此配置),关键代码看下图

8888

 

> 问:refresh_token功能可以禁用吗?

答:可以,首先要求client_details的grant_type不支持 refresh_token,即authorized_grant_types字段中无 refresh_token,其次在配置OAuth2的DefaultTokenServices时将supportRefreshToken配置为false即可,关键代码看下图

222

 

> 问:默认的 access_token有效时间是多少?默认的 refresh_token有效时间是多少?在哪看

答:默认access_token有效时间为12小时,默认refresh_token有效时间为30天,这两默认值在OAuth2的DefaultTokenServices中定义的,如下图:

3333

若想改变默认值,只需要在定义client_details是修改字段access_token_validity (access_token有效时间)与 refresh_token_validity (refresh_token有效时间),单位为:秒

 

> 问:可否在每次调用 refresh token操作时重新生成一个 refresh_token值?若可以如何做

答:可以支持此功能,具体为在配置OAuth2的DefaultTokenServices时将reuseRefreshToken属性配置为fasle即可(默认true),关键代码看下图

44

 

> 问:能否在生成access_token后加自己扩展的代码逻辑?若能如何做

答:可以加自己的扩展逻辑。首先需要写一个类实现接口 TokenEnhancer.java ,实现方法 enhance方法,一示例如下:

555

其次在配置 OAuth2的DefaultTokenServices时增加tokenEnhancer属性配置,关联扩展实现的类即可,关键代码如下

6666

实际上Spring Security OAuth2中实现JWT从而支持OIDC流程就是扩展TokenEnhancer.java来实现的(有一个实现类 JwtAccessTokenConverter.java)

 

> 问:生成access_token值是一UUID值吧?能否不使用UUID值,想扩展如何办?

答:确实生成的access_token是一UUID值,若要扩展不使用UUID,需要这样做:首先写一个子类继承DefaultTokenServices.java,其次将DefaultTokenServices.java的源代码复制到扩展的子类中,并修改createAccessToken方法与createRefreshToken方法中的代码(如此做是因为两方法定义的private的),关键代码如下

7777

另一种办法是通过扩展TokenEnhancer.java 来实现(详细见上一问答)

 

> 问:如何提高 access_token, refresh_token的性能,默认存储在数据库中在高并发大数据时数据库连接会成为性能瓶颈的

答:在大数据高并发环境时,建议使用Redis,将access_token, refresh_token存储在Redis中实现,具体在配置OAuth2的TokenStore时使用子类 RedisTokenStore(默认使用的子类为JdbcTokenStore),更多信息请查看 http://andaily.com/blog/?p=19776