This is an automated email from the ASF dual-hosted git repository. mabin pushed a commit to branch houserush-sample in repository https://gitbox.apache.org/repos/asf/servicecomb-samples.git
commit db8821565eb92ad727d0cc0076d231fa7c87d4ce Author: liubao <[email protected]> AuthorDate: Fri May 17 17:12:32 2019 +0800 using oauth 2 password mode to grant tokens --- authentication/README.md | 4 +- .../TokenEndpoint.java} | 68 +++++++++++++--------- .../authentication/{api => server}/Token.java | 2 +- .../TokenConst.java} | 23 +++----- .../TokenService.java} | 19 ++---- .../edge/AuthenticationEndpoint.java | 44 -------------- .../edge/CustomVertxRestDispatcher.java | 1 + ...cecomb.transport.rest.vertx.VertxHttpDispatcher | 2 +- .../authentication/AuthenticationTestCase.java | 12 ++-- .../authentication/BootEventListener.java | 12 ++-- .../authentication/gateway/ApiDispatcher.java | 1 + .../src/main/resources/microservice.yaml | 2 +- 12 files changed, 74 insertions(+), 116 deletions(-) diff --git a/authentication/README.md b/authentication/README.md index 2274bb4..6d477bb 100644 --- a/authentication/README.md +++ b/authentication/README.md @@ -87,4 +87,6 @@ http://localhost:9093/v1/test/start 测试项目同时展示了这个项目的功能,比如: AuthenticationTestCase 的测试逻辑展示了基本的认证功能,从登陆,到接口的权限检查。 - +# TODO LIST +1. provide TLS for authentication server & edge service +2. grant scope for INTERNAL access & EXTERNAL access diff --git a/authentication/api/authentication-server/endpoint/src/main/java/org/apache/servicecomb/authentication/api/AuthenticationEndpoint.java b/authentication/api/authentication-server/endpoint/src/main/java/org/apache/servicecomb/authentication/server/TokenEndpoint.java similarity index 51% rename from authentication/api/authentication-server/endpoint/src/main/java/org/apache/servicecomb/authentication/api/AuthenticationEndpoint.java rename to authentication/api/authentication-server/endpoint/src/main/java/org/apache/servicecomb/authentication/server/TokenEndpoint.java index c777bc5..67c7ba4 100644 --- a/authentication/api/authentication-server/endpoint/src/main/java/org/apache/servicecomb/authentication/api/AuthenticationEndpoint.java +++ b/authentication/api/authentication-server/endpoint/src/main/java/org/apache/servicecomb/authentication/server/TokenEndpoint.java @@ -15,26 +15,32 @@ * limitations under the License. */ -package org.apache.servicecomb.authentication.api; +package org.apache.servicecomb.authentication.server; + +import java.util.Map; + +import javax.ws.rs.core.MediaType; import org.apache.servicecomb.authentication.jwt.JWTClaims; import org.apache.servicecomb.authentication.jwt.JsonParser; import org.apache.servicecomb.provider.rest.common.RestSchema; +import org.apache.servicecomb.swagger.invocation.exception.InvocationException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.jwt.Jwt; import org.springframework.security.jwt.JwtHelper; import org.springframework.security.jwt.crypto.sign.Signer; import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; -@RestSchema(schemaId = "AuthenticationEndpoint") -@RequestMapping(path = "/v1/auth") -public class AuthenticationEndpoint implements AuthenticationService { +@RestSchema(schemaId = "TokenEndpoint") +@RequestMapping(path = "/v1/oauth/token") +public class TokenEndpoint implements TokenService { @Autowired @Qualifier("authUserDetailsService") private UserDetailsService userDetailsService; @@ -48,33 +54,41 @@ public class AuthenticationEndpoint implements AuthenticationService { private Signer signer; @Override - @PostMapping(path = "login") - public Token login(@RequestParam(name = "userName") String userName, - @RequestParam(name = "password") String password) { - UserDetails userDetails = userDetailsService.loadUserByUsername(userName); - if (passwordEncoder.matches(password, userDetails.getPassword())) { - JWTClaims claims = new JWTClaims(); - if (userDetails.getAuthorities() != null) { - userDetails.getAuthorities().forEach(authority -> claims.addAuthority(authority.getAuthority())); - } - String content = JsonParser.unparse(claims); - Jwt accessToken = JwtHelper.encode(content, signer); + @PostMapping(path = "/", consumes = MediaType.APPLICATION_FORM_URLENCODED) + public Token getAccessToken(@RequestBody Map<String, String> parameters) { + String grantType = parameters.get(TokenConst.PARAM_GRANT_TYPE); + + if (TokenConst.GRANT_TYPE_PASSWORD.equals(grantType)) { + + String username = parameters.get(TokenConst.PARAM_USERNAME); + String password = parameters.get(TokenConst.PARAM_PASSWORD); - Token token = new Token(); - token.setScope(claims.getScope()); - token.setExpires_in(10 * 60); - token.setToken_type("bearer"); - token.setAccess_token(accessToken.getEncoded()); - return token; + try { + UserDetails userDetails = userDetailsService.loadUserByUsername(username); + if (passwordEncoder.matches(password, userDetails.getPassword())) { + JWTClaims claims = new JWTClaims(); + if (userDetails.getAuthorities() != null) { + userDetails.getAuthorities().forEach(authority -> claims.addAuthority(authority.getAuthority())); + } + String content = JsonParser.unparse(claims); + Jwt accessToken = JwtHelper.encode(content, signer); + + Token token = new Token(); + token.setScope(claims.getScope()); + token.setExpires_in(10 * 60); + token.setToken_type("bearer"); + token.setAccess_token(accessToken.getEncoded()); + return token; + } else { + return null; + } + } catch (UsernameNotFoundException e) { + throw new InvocationException(403, "", "forbidden"); + } } else { return null; } - } - @Override - @PostMapping(path = "refresh") - public Token refresh(@RequestParam(name = "refreshToken") String refreshToken) { - return null; } } diff --git a/authentication/api/authentication-server/service/src/main/java/org/apache/servicecomb/authentication/api/Token.java b/authentication/api/authentication-server/service/src/main/java/org/apache/servicecomb/authentication/server/Token.java similarity index 97% rename from authentication/api/authentication-server/service/src/main/java/org/apache/servicecomb/authentication/api/Token.java rename to authentication/api/authentication-server/service/src/main/java/org/apache/servicecomb/authentication/server/Token.java index 94ce237..8758bd1 100644 --- a/authentication/api/authentication-server/service/src/main/java/org/apache/servicecomb/authentication/api/Token.java +++ b/authentication/api/authentication-server/service/src/main/java/org/apache/servicecomb/authentication/server/Token.java @@ -15,7 +15,7 @@ * limitations under the License. */ -package org.apache.servicecomb.authentication.api; +package org.apache.servicecomb.authentication.server; import java.util.Map; import java.util.Set; diff --git a/authentication/api/authentication-server/service/src/main/java/org/apache/servicecomb/authentication/api/AuthenticationService.java b/authentication/api/authentication-server/service/src/main/java/org/apache/servicecomb/authentication/server/TokenConst.java similarity index 59% copy from authentication/api/authentication-server/service/src/main/java/org/apache/servicecomb/authentication/api/AuthenticationService.java copy to authentication/api/authentication-server/service/src/main/java/org/apache/servicecomb/authentication/server/TokenConst.java index 77635ad..a46a7b9 100644 --- a/authentication/api/authentication-server/service/src/main/java/org/apache/servicecomb/authentication/api/AuthenticationService.java +++ b/authentication/api/authentication-server/service/src/main/java/org/apache/servicecomb/authentication/server/TokenConst.java @@ -15,21 +15,14 @@ * limitations under the License. */ -package org.apache.servicecomb.authentication.api; +package org.apache.servicecomb.authentication.server; -public interface AuthenticationService { - /** - * login using user name and password. - * @param userName user name - * @param password password - * @return After successfully login, token is created. Or null is returned. - */ - Token login(String userName, String password); +public class TokenConst { + public static final String PARAM_GRANT_TYPE = "grant_type"; - /** - * acquired new token using refresh token. - * @param refreshToken refresh token - * @return After successfully authenticated, token is created. Or null is returned. - */ - Token refresh(String refreshToken); + public static final String PARAM_USERNAME = "username"; + + public static final String PARAM_PASSWORD = "password"; + + public static final String GRANT_TYPE_PASSWORD = "password"; } diff --git a/authentication/api/authentication-server/service/src/main/java/org/apache/servicecomb/authentication/api/AuthenticationService.java b/authentication/api/authentication-server/service/src/main/java/org/apache/servicecomb/authentication/server/TokenService.java similarity index 59% rename from authentication/api/authentication-server/service/src/main/java/org/apache/servicecomb/authentication/api/AuthenticationService.java rename to authentication/api/authentication-server/service/src/main/java/org/apache/servicecomb/authentication/server/TokenService.java index 77635ad..b0cea22 100644 --- a/authentication/api/authentication-server/service/src/main/java/org/apache/servicecomb/authentication/api/AuthenticationService.java +++ b/authentication/api/authentication-server/service/src/main/java/org/apache/servicecomb/authentication/server/TokenService.java @@ -15,21 +15,10 @@ * limitations under the License. */ -package org.apache.servicecomb.authentication.api; +package org.apache.servicecomb.authentication.server; -public interface AuthenticationService { - /** - * login using user name and password. - * @param userName user name - * @param password password - * @return After successfully login, token is created. Or null is returned. - */ - Token login(String userName, String password); +import java.util.Map; - /** - * acquired new token using refresh token. - * @param refreshToken refresh token - * @return After successfully authenticated, token is created. Or null is returned. - */ - Token refresh(String refreshToken); +public interface TokenService { + Token getAccessToken(Map<String, String> parameters); } diff --git a/authentication/api/edge-service/endpoint/src/main/java/org/apache/servicecomb/authentication/edge/AuthenticationEndpoint.java b/authentication/api/edge-service/endpoint/src/main/java/org/apache/servicecomb/authentication/edge/AuthenticationEndpoint.java deleted file mode 100644 index 68fe5d7..0000000 --- a/authentication/api/edge-service/endpoint/src/main/java/org/apache/servicecomb/authentication/edge/AuthenticationEndpoint.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.servicecomb.authentication.edge; - -import org.apache.servicecomb.authentication.api.AuthenticationService; -import org.apache.servicecomb.authentication.api.Token; -import org.apache.servicecomb.provider.pojo.RpcReference; -import org.apache.servicecomb.provider.rest.common.RestSchema; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; - -@RestSchema(schemaId = "AuthenticationEndpoint") -@RequestMapping(path = "/v1/auth") -public class AuthenticationEndpoint { - @RpcReference(microserviceName = "authentication-server", schemaId = "AuthenticationEndpoint") - private AuthenticationService authenticationService; - - @PostMapping(path = "login") - public Token login(@RequestParam(name = "userName") String userName, - @RequestParam(name = "password") String password) { - return authenticationService.login(userName, password); - } - - @PostMapping(path = "refresh") - public Token refresh(@RequestParam(name = "refreshToken") String refreshToken) { - return authenticationService.refresh(refreshToken); - } -} diff --git a/authentication/api/edge-service/service/src/main/java/org/apache/servicecomb/authentication/edge/CustomVertxRestDispatcher.java b/authentication/api/edge-service/service/src/main/java/org/apache/servicecomb/authentication/edge/CustomVertxRestDispatcher.java index d1c6ef4..521b71c 100644 --- a/authentication/api/edge-service/service/src/main/java/org/apache/servicecomb/authentication/edge/CustomVertxRestDispatcher.java +++ b/authentication/api/edge-service/service/src/main/java/org/apache/servicecomb/authentication/edge/CustomVertxRestDispatcher.java @@ -45,6 +45,7 @@ import io.vertx.ext.web.RoutingContext; import io.vertx.ext.web.handler.CookieHandler; // copied from org.apache.servicecomb.transport.rest.vertx.VertxRestDispatcher 1.2.0 +// TODO: using 1.2.2+ to make it simpler public class CustomVertxRestDispatcher extends AbstractVertxHttpDispatcher { private static final Logger LOGGER = LoggerFactory.getLogger(VertxRestDispatcher.class); diff --git a/authentication/api/edge-service/service/src/main/resources/META-INF/services/org.apache.servicecomb.transport.rest.vertx.VertxHttpDispatcher b/authentication/api/edge-service/service/src/main/resources/META-INF/services/org.apache.servicecomb.transport.rest.vertx.VertxHttpDispatcher index 53481f1..32c1583 100644 --- a/authentication/api/edge-service/service/src/main/resources/META-INF/services/org.apache.servicecomb.transport.rest.vertx.VertxHttpDispatcher +++ b/authentication/api/edge-service/service/src/main/resources/META-INF/services/org.apache.servicecomb.transport.rest.vertx.VertxHttpDispatcher @@ -15,4 +15,4 @@ # limitations under the License. # -org.apache.servicecomb.authentication.edge.CustomVertxRestDispatcher \ No newline at end of file +# org.apache.servicecomb.authentication.edge.CustomVertxRestDispatcher \ No newline at end of file diff --git a/authentication/samples/Client/src/main/java/org/apache/servicecomb/authentication/AuthenticationTestCase.java b/authentication/samples/Client/src/main/java/org/apache/servicecomb/authentication/AuthenticationTestCase.java index 61ba97f..50a4519 100644 --- a/authentication/samples/Client/src/main/java/org/apache/servicecomb/authentication/AuthenticationTestCase.java +++ b/authentication/samples/Client/src/main/java/org/apache/servicecomb/authentication/AuthenticationTestCase.java @@ -17,7 +17,7 @@ package org.apache.servicecomb.authentication; -import org.apache.servicecomb.authentication.api.Token; +import org.apache.servicecomb.authentication.server.Token; import org.springframework.http.HttpEntity; import org.springframework.http.HttpHeaders; import org.springframework.http.MediaType; @@ -38,13 +38,14 @@ public class AuthenticationTestCase implements TestCase { private void testHanlderAuth() { // get token MultiValueMap<String, Object> map = new LinkedMultiValueMap<>(); - map.add("userName", "admin"); + map.add("grant_type", "password"); + map.add("username", "admin"); map.add("password", "changeMyPassword"); HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.MULTIPART_FORM_DATA); Token token = - BootEventListener.gateEndpoint.postForObject("/v1/auth/login", + BootEventListener.authenticationServerTokenEndpoint.postForObject("/", new HttpEntity<>(map, headers), Token.class); TestMgr.check("bearer", token.getToken_type()); @@ -85,13 +86,14 @@ public class AuthenticationTestCase implements TestCase { private void testMethodAuth() { // get token MultiValueMap<String, Object> map = new LinkedMultiValueMap<>(); - map.add("userName", "admin"); + map.add("grant_type", "password"); + map.add("username", "admin"); map.add("password", "changeMyPassword"); HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.MULTIPART_FORM_DATA); Token token = - BootEventListener.gateEndpoint.postForObject("/v1/auth/login", + BootEventListener.authenticationServerTokenEndpoint.postForObject("/", new HttpEntity<>(map, headers), Token.class); TestMgr.check("bearer", token.getToken_type()); diff --git a/authentication/samples/Client/src/main/java/org/apache/servicecomb/authentication/BootEventListener.java b/authentication/samples/Client/src/main/java/org/apache/servicecomb/authentication/BootEventListener.java index 5512f8c..08d1bb3 100644 --- a/authentication/samples/Client/src/main/java/org/apache/servicecomb/authentication/BootEventListener.java +++ b/authentication/samples/Client/src/main/java/org/apache/servicecomb/authentication/BootEventListener.java @@ -22,7 +22,7 @@ import org.springframework.stereotype.Component; @Component public class BootEventListener implements BootListener { - public static GateRestTemplate authenticationServerAuthenticationEndpoint; + public static GateRestTemplate authenticationServerTokenEndpoint; public static GateRestTemplate gateEndpoint; public static GateRestTemplate resouceServerHandlerAuthEndpoint; public static GateRestTemplate resouceServerMethodAuthEndpoint; @@ -30,14 +30,14 @@ public class BootEventListener implements BootListener { @Override public void onBootEvent(BootEvent event) { if (EventType.AFTER_REGISTRY.equals(event.getEventType())) { - authenticationServerAuthenticationEndpoint = - GateRestTemplate.createEdgeRestTemplate("gateway", "authentication-server", "AuthenticationEndpoint").init(); + authenticationServerTokenEndpoint = + GateRestTemplate.createEdgeRestTemplate("edge-service", "authentication-server", "TokenEndpoint").init(); gateEndpoint = - GateRestTemplate.createEdgeRestTemplate("gateway", null, null).init(); + GateRestTemplate.createEdgeRestTemplate("edge-service", null, null).init(); resouceServerHandlerAuthEndpoint = - GateRestTemplate.createEdgeRestTemplate("gateway", "resource-server", "HandlerAuthEndpoint").init(); + GateRestTemplate.createEdgeRestTemplate("edge-service", "resource-server", "HandlerAuthEndpoint").init(); resouceServerMethodAuthEndpoint = - GateRestTemplate.createEdgeRestTemplate("gateway", "resource-server", "PreMethodAuthEndpoint").init(); + GateRestTemplate.createEdgeRestTemplate("edge-service", "resource-server", "PreMethodAuthEndpoint").init(); } } diff --git a/authentication/samples/EdgeService/src/main/java/org/apache/servicecomb/authentication/gateway/ApiDispatcher.java b/authentication/samples/EdgeService/src/main/java/org/apache/servicecomb/authentication/gateway/ApiDispatcher.java index 9f45550..7642268 100644 --- a/authentication/samples/EdgeService/src/main/java/org/apache/servicecomb/authentication/gateway/ApiDispatcher.java +++ b/authentication/samples/EdgeService/src/main/java/org/apache/servicecomb/authentication/gateway/ApiDispatcher.java @@ -27,6 +27,7 @@ import io.vertx.ext.web.Router; import io.vertx.ext.web.RoutingContext; import io.vertx.ext.web.handler.CookieHandler; +//TODO: using 1.2.2+ to make it simpler public class ApiDispatcher extends AbstractEdgeDispatcher { @Override public int getOrder() { diff --git a/authentication/samples/EdgeService/src/main/resources/microservice.yaml b/authentication/samples/EdgeService/src/main/resources/microservice.yaml index 2eda242..7531d52 100644 --- a/authentication/samples/EdgeService/src/main/resources/microservice.yaml +++ b/authentication/samples/EdgeService/src/main/resources/microservice.yaml @@ -22,7 +22,7 @@ servicecomb-config-order: 100 APPLICATION_ID: authentication-application service_description: version: 0.0.1 - name: gateway + name: edge-service environment: development servicecomb:
