You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@servicecomb.apache.org by li...@apache.org on 2019/06/18 12:39:47 UTC

[servicecomb-fence] 02/09: [SCB-1292]Add developers guide for servicecomb-fence and fix authSignatureVerifier

This is an automated email from the ASF dual-hosted git repository.

liubao pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/servicecomb-fence.git

commit 46de410996ac63012ed1237acf21e37eae3b321f
Author: liubao <bi...@qq.com>
AuthorDate: Fri May 24 17:19:49 2019 +0800

    [SCB-1292]Add developers guide for servicecomb-fence and fix authSignatureVerifier
---
 README.md                                          | 108 +++-------
 .../server/RefreshTokenTokenGranter.java           |   6 +-
 .../authentication/edge/AuthHandler.java           |   2 +-
 .../resource/ResourceAuthHandler.java              |   2 +-
 docs/en_US/developersGuide.md                      |   1 +
 docs/zh_CN/developersGuide.md                      | 219 +++++++++++++++++++++
 .../AuthenticationConfiguration.java               |   9 +-
 samples/EdgeService/pom.xml                        |   4 -
 .../gateway/AuthenticationConfiguration.java       |   4 +-
 .../resource/AuthenticationConfiguration.java      |   6 +-
 10 files changed, 258 insertions(+), 103 deletions(-)

diff --git a/README.md b/README.md
index c91d67e..8befb72 100644
--- a/README.md
+++ b/README.md
@@ -1,110 +1,54 @@
-This project demonstrates authentications and authorizations based on JWT/OAuth2. Projct names follow OAuth2 architecture. 
+# English
 
-## Implementations
+This project is servicecomb-java-chassis security support. The main architecture is based on [The OAuth 2.0 Authorization Framework](https://tools.ietf.org/html/rfc6749) and [OpenID Connect](https://openid.net/connect/). And provides APIs for developers based on [Spring Security](https://spring.io/projects/spring-security). Please see [developers guide](docs/en_US/developersGuide.md) for details.
 
-This project uses spring security API and mainly designed for ServiceComb architecture.
+## Project description
 
-* User Management
+This project contains two folders api and samples. Api folder contains components used in Authentication Server, Edge Service and Resource Server. And samples folder gives a working example showing how to use these apis. 
 
-  1. UserDetailsService: load users information
-  2. UserDetails: User information
-  3. GrantedAuthority: authorities
-  4. PasswordEncoder: encode or verify user password
+* Build and run
 
-## Project
-
-* AuthenticationServer
-
-Authentication server implementation. Provides APIs to login, and query roles, etc. 
-
-
-* Gateway
-
-Check if users are authenticated and dispatch HTTP request.
-
-* Client
-
-Demonstrates how client uses this project. Integration tests are provided. 
-
-
-* Api
-Reusable part. 
+```
+cd samples
+mvn clean install
+```
 
-* For testing
+After build, the Authentication Server, Resource Server, Edge Service and Testing Client runnable jar are generated, start and run the four services.
 
-Run AuthenticationServer、Gateway、Client、ResourceServer and call
+* Run tests
 
+After services are started, try
 ```
 http://localhost:9093/v1/test/start
 ```
 
-see AuthenticationTestCase for details.
-
-
-本项目提供认证鉴权服务的实现,主要提供了基于角色的权限管理,和基于JWT的微服务授权模式。微服务的命名参考了OAuth2协议里面的命名方式。可以参考[OAuth2.0原理和验证流程分析](https://www.jianshu.com/p/d74ce6ca0c33)对于OAuth2认证过程的介绍,本项目的认证过程非常类似OAuth2的密码模式。
+see AuthenticationTestCase for testing details.
 
-项目的目标是提供一个商业可用的鉴权实现,对于项目代码实现的问题可以提交issue,本项目也接纳PR,共同完善。
 
+# 中文
+本项目为servicecomb-java-chassis提供认证鉴权支持。鉴权实现的主要框架参考了[The OAuth 2.0 Authorization Framework](https://tools.ietf.org/html/rfc6749) 和 [OpenID Connect](https://openid.net/connect/)。项目参考[Spring Security](https://spring.io/projects/spring-security)给开发者提供了接口。请参考[开发指南](docs/zh_CN/developersGuide.md)获取详细信息。
 
+## 项目说明
 
-## 实现说明
+项目包含了api和samples两个目录。其中api目录主要提供给Authentication Server, Edge Service and Resource Server使用的api。 samples目录是基于上诉api提供的一个开发示例。
 
-* 用户管理
-用户管理采用了org.springframework.security.core.userdetails的模型,包括:
-  1. UserDetailsService:加载用户信息。
-  2. UserDetails:用户信息。
-  3. GrantedAuthority:角色信息。
-  4. PasswordEncoder:用户密码加密和匹配。
-  
-  
-## 项目结构介绍
+* 编译和运行
 
-* AuthenticationServer
 
-认证鉴权服务。提供用户管理、角色管理。并提供登录认证、权限查询等接口。鉴权服务及相关API是核心交付件,也是能够被重用的部分。开发者可以基于这个项目开发认证鉴权服务。
-
-* Gateway
-提供请求拦截,校验用户是否已经经过认证。一方面演示网关如何和配套鉴权服务完成开发,本项目也是自动化测试的组成部分。
-
-* Client
-Client模拟的是使用使用者。一方面演示客户端如何获取Token,本项目也是自动化测试的组成部分。
-
-* ResourceServer
-ResourceServer模拟的是业务服务。一方面演示业务服务如何进行权限配置,本项目也是自动化测试的组成部分。
-
-* Api
-认证鉴权提取的公共功能,作为复用单元。目前项目处于初始阶段,很多复用代码分散在其他项目中。
+```
+cd samples
+mvn clean install
+```
 
+编译完成后,会生成Authentication Server, Resource Server, Edge Service and Testing Client可执行jar包,运行这四个服务。
 
-* 测试介绍
+* 运行测试用例
 
-本项目实现了微服务架构的自动化测试。启动AuthenticationServer、Gateway、Client、ResourceServer后,可以提供
+当四个服务都运行起来后,访问:
 
 ```
 http://localhost:9093/v1/test/start
 ```
-触发测试用例的执行。 所有的测试用例放到Client微服务里面, 这个微服务实现了简单的测试框架帮助书写测试用例,对测试结果进行检查等功能。 
-
-测试项目同时展示了这个项目的功能,比如: AuthenticationTestCase 的测试逻辑展示了基本的认证功能,从登陆,到接口的权限检查。 
-
-# TODO LIST
-1. provide TLS for authentication server & edge service
-2. grant scope for INTERNAL access & EXTERNAL access 
-3. access token support: a. use access token to get optional scope or roles token. 这个可以解决角色过多的时候, token过大的一些问题
-4. 实现注销逻辑(会话管理)
-5. 支持分层的角色机制
-
-       ROLE_LEVEL1
-        /       \
-   ROLE_LEVEL2  ROLE_LEVEL2
-
- TOKEN里面只返回ROLE_LEVEL1,设置为ROLE_LEVEL2访问的操作,也可以访问。
-
-6. REFRESH_TOKEN可以用来实现申请不同SCOPE的TOKEN。 
-7. 设计目标:无状态。认证服务器和资源服务器均可以多实例部署,每个实例之间不共享状态。在实现很多功能的时候,都遵循这个约束。包括通过refresh token获取新的access token的时候。遵循这个约束,意味着请求需要同时传递refresh token和access token。 
-8, 重新设计TOKEN(代码重构、支持会话管理),支持OpenID Connect。
-
-OAUTH的不好的地方:TOKEN在有效期内,容易被利用,无法注销;TOKEN过期后,必须重新认证,和用户是否在一直操作无关,体验不好,虽然可以通过refresh_token获取新的token提升体验,但是refresh_token有效期如果设置的太长,会降低安全性。Token在有效期内,如果修改了权限等信息,无法及时感知,需要重新登录。
-OAUTH的好的地方:TOKEN签发、认证都可以由微服务实例独自完成,不需要共用的数据存储,比如数据库、Redis等,效率更高,弹性扩容。
 
+可以通过查看AuthenticationTestCase了解测试用例的详情。
 
diff --git a/api/authentication-server/endpoint/src/main/java/org/apache/servicecomb/authentication/server/RefreshTokenTokenGranter.java b/api/authentication-server/endpoint/src/main/java/org/apache/servicecomb/authentication/server/RefreshTokenTokenGranter.java
index ffbf9c5..7a41e90 100644
--- a/api/authentication-server/endpoint/src/main/java/org/apache/servicecomb/authentication/server/RefreshTokenTokenGranter.java
+++ b/api/authentication-server/endpoint/src/main/java/org/apache/servicecomb/authentication/server/RefreshTokenTokenGranter.java
@@ -25,8 +25,8 @@ import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Qualifier;
 import org.springframework.security.jwt.Jwt;
 import org.springframework.security.jwt.JwtHelper;
+import org.springframework.security.jwt.crypto.sign.SignatureVerifier;
 import org.springframework.security.jwt.crypto.sign.Signer;
-import org.springframework.security.jwt.crypto.sign.SignerVerifier;
 import org.springframework.stereotype.Component;
 
 import com.netflix.config.DynamicPropertyFactory;
@@ -34,8 +34,8 @@ import com.netflix.config.DynamicPropertyFactory;
 @Component(value = "fefreshTokenTokenGranter")
 public class RefreshTokenTokenGranter implements TokenGranter {
   @Autowired
-  @Qualifier("authSignerVerifier")
-  private SignerVerifier signerVerifier;
+  @Qualifier("authSignatureVerifier")
+  private SignatureVerifier signerVerifier;
 
   @Autowired
   @Qualifier("authSigner")
diff --git a/api/edge-service/service/src/main/java/org/apache/servicecomb/authentication/edge/AuthHandler.java b/api/edge-service/service/src/main/java/org/apache/servicecomb/authentication/edge/AuthHandler.java
index 40ef32d..abf4587 100644
--- a/api/edge-service/service/src/main/java/org/apache/servicecomb/authentication/edge/AuthHandler.java
+++ b/api/edge-service/service/src/main/java/org/apache/servicecomb/authentication/edge/AuthHandler.java
@@ -38,7 +38,7 @@ public class AuthHandler implements Handler {
     }
     Jwt jwt = JwtHelper.decode(token);
     try {
-      jwt.verifySignature(BeanUtils.getBean("authSignerVerifier"));
+      jwt.verifySignature(BeanUtils.getBean("authSignatureVerifier"));
     } catch (InvalidSignatureException e) {
       asyncResponse.consumerFail(new InvocationException(403, "forbidden", "not authenticated"));
       return;
diff --git a/api/resource-server/service/src/main/java/org/apache/servicecomb/authentication/resource/ResourceAuthHandler.java b/api/resource-server/service/src/main/java/org/apache/servicecomb/authentication/resource/ResourceAuthHandler.java
index 1d8e32b..68c6960 100644
--- a/api/resource-server/service/src/main/java/org/apache/servicecomb/authentication/resource/ResourceAuthHandler.java
+++ b/api/resource-server/service/src/main/java/org/apache/servicecomb/authentication/resource/ResourceAuthHandler.java
@@ -59,7 +59,7 @@ public class ResourceAuthHandler implements Handler {
     Jwt jwt = JwtHelper.decode(token);
     JWTClaims claims;
     try {
-      jwt.verifySignature(BeanUtils.getBean("authSignerVerifier"));
+      jwt.verifySignature(BeanUtils.getBean("authSignatureVerifier"));
       claims = JsonParser.parse(jwt.getClaims(), JWTClaims.class);
       // TODO: verify claims.
     } catch (Exception e) {
diff --git a/docs/en_US/developersGuide.md b/docs/en_US/developersGuide.md
new file mode 100644
index 0000000..f87f5c1
--- /dev/null
+++ b/docs/en_US/developersGuide.md
@@ -0,0 +1 @@
+# TODO
\ No newline at end of file
diff --git a/docs/zh_CN/developersGuide.md b/docs/zh_CN/developersGuide.md
new file mode 100644
index 0000000..013f98f
--- /dev/null
+++ b/docs/zh_CN/developersGuide.md
@@ -0,0 +1,219 @@
+# servicecomb-fence 开发指南
+
+开发者可以使用 servicecomb-fence 给 servicecomb-java-chassis 微服务项目增加基于 OpenID Connect 的认证鉴权能力。
+
+## 认证鉴权流程介绍
+
+### 密码模式
+
+  * Client 输入用户名密码向 Authentication Server 请求 Token。
+
+```
+** HTTP Request **
+
+POST http://localhost:9090/api/authentication-server/v1/oauth/token HTTP/1.1
+Content-Type: application/x-www-form-urlencoded
+
+grant_type=password&username=admin&password=changeMyPassword
+```
+
+  * Authentication Server 发送 Token 给 Client 。
+
+  * Client 携带 Token 请求 Resource Server 。
+
+```
+** HTTP Request **
+
+POST http://localhost:9090/api/resource-server/v1/auth/handler/adminSayHello?name=Hi HTTP/1.1
+Content-Type: application/x-www-form-urlencoded
+Authorization: Bearer czZCaGRSa3F0MzpnWDFmQmF0M2JW
+```
+
+  * Resource Server 返回对应的资源给 Client 。 
+
+## 开发 Authentication Server
+
+Authentication Server 主要提供认证和授权等接口。  
+
+* 配置依赖
+
+项目中引入
+
+```
+    <dependency>
+      <groupId>org.apache.servicecomb.authentication</groupId>
+      <artifactId>authentication-server-api-endpoint</artifactId>
+    </dependency>
+```
+
+* 配置
+
+Authentication Server 需要配置 PasswordEncoder、Signer、SignerVerifier、UserDetailsService 等。这些对象和 Spring Security的概念一样。
+```
+@Configuration
+public class AuthenticationConfiguration {
+  @Autowired
+  @Qualifier("authPasswordEncoder")
+  private PasswordEncoder passwordEncoder;
+
+  @Bean(name = "authPasswordEncoder")
+  public PasswordEncoder authPasswordEncoder() {
+    return new Pbkdf2PasswordEncoder();
+  }
+
+  @Bean(name = "authSigner")
+  public Signer authSigner() {
+    return authSignerVerifier();
+  }
+  
+  @Bean(name = "authSignerVerifier")
+  public SignerVerifier authSignerVerifier() {
+    return new MacSigner("Please change this key.");
+  }
+
+  @Bean(name = "authUserDetailsService")
+  public UserDetailsService authUserDetailsService() {
+    InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
+    UserDetails uAdmin = new User("admin", passwordEncoder.encode("changeMyPassword"),
+        Arrays.asList(new SimpleGrantedAuthority("ADMIN")));
+    UserDetails uGuest = new User("guest", passwordEncoder.encode("changeMyPassword"),
+        Arrays.asList(new SimpleGrantedAuthority("GUEST")));
+    manager.createUser(uAdmin);
+    manager.createUser(uGuest);
+    return manager;
+  }
+}
+```
+
+* UserDetailsService
+
+获取用户详情,包括用户名称、角色等信息。包括 InMemoryUserDetailsManager 、 JdbcUserDetailsManager 等实现。示例项目使用了InMemoryUserDetailsManager , 它不会持久化, 正式项目需要使用 JdbcUserDetailsManager 等。
+
+* Signer 和  SignatureVerifier 
+
+生成 Token 和对 Token 进行校验。Singer 和  SignatureVerifier 是配套使用的, 在 Authentication Server , 生成 Token 的时候,需要使用 Singer 。 验证 Token 的有效性 (比如查询 userDetails 等场景), 需要使用  SignatureVerifier 。 通常有两种方式进行签名和校验, 一种是基于对称秘钥的机制,比如MacSigner,即是 Singer, 也是 SignatureVerifier (SignerVerifier); 一种是基于非对称秘钥的机制, 比如 RsaSigner 和  RsaVerifier , 生成 Token 和校验 Token 的秘钥是不同的。
+
+* PasswordEncoder 
+
+从 UserDetailsService 校验用户密码的时候需要使用。 开发者需要在加密性能和保密程度方面选择合适的算法。 常用的有 Pbkdf2PasswordEncoder , 它可以设置迭代次数,能够更好的保护密码不被暴力破解。 
+
+## 开发 Resource Server
+
+Resource Server 对 Client 的访问进行认证, 并进行权限控制。 
+
+* 配置依赖
+
+项目中引入
+
+```
+    <dependency>
+      <groupId>org.apache.servicecomb.authentication</groupId>
+      <artifactId>authentication-resource-api-endpoint</artifactId>
+    </dependency>
+```
+
+* 配置
+
+Resource Server 需要配置 SignatureVerifier 等, 对用户会话进行认证。 
+```
+@Configuration
+public class AuthenticationConfiguration {
+  @Bean(name = "authSignatureVerifier")
+  public SignerVerifier authSignatureVerifier() {
+    return new MacSigner("Please change this key.");
+  }
+}
+```
+
+* 权限配置
+
+fence 提供了两种方式进行权限配置。 一种是基于配置文件的,一种是基于 Annotation 。
+
+基于文件的配置, 在 microservice.yaml 中可以配置每个方法的访问权限。 
+
+```
+servicecomb:
+  authencation:
+    access:
+      needAuth: true
+      roles:
+        HandlerAuthEndpoint:
+          adminSayHello: ADMIN
+          guestSayHello: GUEST
+          guestOrAdminSayHello: ADMIN,GUEST
+          # everyoneSayHello: all can
+```
+
+还可以统一配置Schema
+
+```
+servicecomb:
+  authencation:
+    access:
+      needAuth: true
+      roles:
+        HandlerAuthEndpoint: ADMIN
+```
+
+或者所有
+
+```
+servicecomb:
+  authencation:
+    access:
+      needAuth: true
+      roles: ADMIN
+```
+
+基于 Annotation , 可以使用 PreAuthorize 标签
+
+```
+@PreAuthorize("hasRole('ADMIN')")
+```
+
+Annotation 支持默认没有启用, 可以通过 EnableGlobalMethodSecurity 标签启用。 
+
+```
+@Configuration
+@EnableGlobalMethodSecurity(
+    prePostEnabled = true)
+public class MethodSecurityConfiguration extends GlobalMethodSecurityConfiguration {
+  @Override
+  protected MethodSecurityExpressionHandler createExpressionHandler() {
+    DefaultMethodSecurityExpressionHandler h = (DefaultMethodSecurityExpressionHandler) super.createExpressionHandler();
+    h.setDefaultRolePrefix("");
+    return h;
+  }
+}
+```
+
+
+## 开发 Edge Service
+
+Edge Service 是微服务接入层。 在[单体应用微服务改造](https://bbs.huaweicloud.com/blogs/17ad483f325f11e9bd5a7ca23e93a891)中介绍了基于网关的弹性架构, 这种架构对于微服务持续演进具有重要意义, 因此建议开发者都按照这个[基础架构](https://bbs.huaweicloud.com/blogs/8bb2c3b8366c11e9bd5a7ca23e93a891)搭建微服务。接入层在认证鉴权的功能包括透传 Authentication Server的请求, 将HTTP消息转化为ServiceComb-java-chassis友好的消息格式,对Token进行认证,控制内部接口和外部接口的隔离等功能。 
+
+* 配置依赖
+
+项目中引入
+
+```
+    <dependency>
+      <groupId>org.apache.servicecomb.authentication</groupId>
+      <artifactId>authentication-edge-api-endpoint</artifactId>
+    </dependency>
+```
+
+* 配置
+
+Edge Service 需要配置 SignatureVerifier 等, 对用户会话进行认证。 
+```
+
+@Configuration
+public class AuthenticationConfiguration {
+  @Bean(name = "authSignatureVerifier")
+  public SignerVerifier authSignatureVerifier() {
+    return new MacSigner("Please change this key.");
+  }
+}
+
+```
diff --git a/samples/AuthenticationServer/src/main/java/org/apache/servicecomb/authentication/AuthenticationConfiguration.java b/samples/AuthenticationServer/src/main/java/org/apache/servicecomb/authentication/AuthenticationConfiguration.java
index 2fdbd4c..b70273f 100644
--- a/samples/AuthenticationServer/src/main/java/org/apache/servicecomb/authentication/AuthenticationConfiguration.java
+++ b/samples/AuthenticationServer/src/main/java/org/apache/servicecomb/authentication/AuthenticationConfiguration.java
@@ -30,7 +30,6 @@ import org.springframework.security.core.userdetails.UserDetailsService;
 import org.springframework.security.crypto.password.PasswordEncoder;
 import org.springframework.security.crypto.password.Pbkdf2PasswordEncoder;
 import org.springframework.security.jwt.crypto.sign.MacSigner;
-import org.springframework.security.jwt.crypto.sign.Signer;
 import org.springframework.security.jwt.crypto.sign.SignerVerifier;
 import org.springframework.security.provisioning.InMemoryUserDetailsManager;
 
@@ -45,12 +44,8 @@ public class AuthenticationConfiguration {
     return new Pbkdf2PasswordEncoder();
   }
 
-  @Bean(name = "authSigner")
-  public Signer authSigner() {
-    return authSignerVerifier();
-  }
-  
-  @Bean(name = "authSignerVerifier")
+  // If using RSA, need to configure authSigner and authSignatureVerifier separately. 
+  @Bean(name = {"authSigner", "authSignatureVerifier" })
   public SignerVerifier authSignerVerifier() {
     return new MacSigner("Please change this key.");
   }
diff --git a/samples/EdgeService/pom.xml b/samples/EdgeService/pom.xml
index cb50f95..e0ecf5c 100644
--- a/samples/EdgeService/pom.xml
+++ b/samples/EdgeService/pom.xml
@@ -56,10 +56,6 @@
       <artifactId>authentication-edge-api-endpoint</artifactId>
     </dependency>
     <dependency>
-      <groupId>org.apache.servicecomb.authentication</groupId>
-      <artifactId>authentication-server-api-service</artifactId>
-    </dependency>
-    <dependency>
       <groupId>org.apache.servicecomb</groupId>
       <artifactId>solution-basic</artifactId>
     </dependency>
diff --git a/samples/EdgeService/src/main/java/org/apache/servicecomb/authentication/gateway/AuthenticationConfiguration.java b/samples/EdgeService/src/main/java/org/apache/servicecomb/authentication/gateway/AuthenticationConfiguration.java
index 1e913fb..510d821 100644
--- a/samples/EdgeService/src/main/java/org/apache/servicecomb/authentication/gateway/AuthenticationConfiguration.java
+++ b/samples/EdgeService/src/main/java/org/apache/servicecomb/authentication/gateway/AuthenticationConfiguration.java
@@ -24,8 +24,8 @@ import org.springframework.security.jwt.crypto.sign.SignerVerifier;
 
 @Configuration
 public class AuthenticationConfiguration {
-  @Bean(name = "authSignerVerifier")
-  public SignerVerifier authSignerVerifier() {
+  @Bean(name = "authSignatureVerifier")
+  public SignerVerifier authSignatureVerifier() {
     return new MacSigner("Please change this key.");
   }
 }
diff --git a/samples/ResourceServer/src/main/java/org/apache/servicecomb/authentication/resource/AuthenticationConfiguration.java b/samples/ResourceServer/src/main/java/org/apache/servicecomb/authentication/resource/AuthenticationConfiguration.java
index 712030d..2074321 100644
--- a/samples/ResourceServer/src/main/java/org/apache/servicecomb/authentication/resource/AuthenticationConfiguration.java
+++ b/samples/ResourceServer/src/main/java/org/apache/servicecomb/authentication/resource/AuthenticationConfiguration.java
@@ -20,12 +20,12 @@ package org.apache.servicecomb.authentication.resource;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
 import org.springframework.security.jwt.crypto.sign.MacSigner;
-import org.springframework.security.jwt.crypto.sign.SignerVerifier;
+import org.springframework.security.jwt.crypto.sign.SignatureVerifier;
 
 @Configuration
 public class AuthenticationConfiguration {
-  @Bean(name = "authSignerVerifier")
-  public SignerVerifier authSignerVerifier() {
+  @Bean(name = "authSignatureVerifier")
+  public SignatureVerifier authSignatureVerifier() {
     return new MacSigner("Please change this key.");
   }
 }