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 79409fb0d66c20c93645fa5e48d392d4a6b4078d Author: liubao <[email protected]> AuthorDate: Mon May 13 15:47:46 2019 +0800 add method security support --- ...onServer.java => AuthenticationServerMain.java} | 2 +- .../{Client.java => AuthenticationClientMain.java} | 2 +- .../authentication/AuthenticationTestCase.java | 52 +++++++++++++++ .../authentication/BootEventListener.java | 4 ++ .../servicecomb/authentication/TestEndpoint.java | 12 ++-- .../apache/servicecomb/authentication/TestMgr.java | 13 ++++ ...wayMain.java => AuthenticationGatewayMain.java} | 2 +- ...ResourceServer.java => ResourceServerMain.java} | 2 +- ...eptionExceptionToProducerResponseConverter.java | 39 +++++++++++ .../resource/MethodSecurityConfiguration.java | 36 ++++++++++ .../resource/PreMethodAuthEndpoint.java | 2 +- .../resource/ResourceAuthHandler.java | 16 ++++- .../resource/SimpleAuthentication.java | 77 ++++++++++++++++++++++ ....exception.ExceptionToProducerResponseConverter | 18 +++++ 14 files changed, 267 insertions(+), 10 deletions(-) diff --git a/authentication/AuthenticationServer/src/main/java/org/apache/servicecomb/authentication/AuthenticationServer.java b/authentication/AuthenticationServer/src/main/java/org/apache/servicecomb/authentication/AuthenticationServerMain.java similarity index 96% rename from authentication/AuthenticationServer/src/main/java/org/apache/servicecomb/authentication/AuthenticationServer.java rename to authentication/AuthenticationServer/src/main/java/org/apache/servicecomb/authentication/AuthenticationServerMain.java index f38125a..35b239d 100644 --- a/authentication/AuthenticationServer/src/main/java/org/apache/servicecomb/authentication/AuthenticationServer.java +++ b/authentication/AuthenticationServer/src/main/java/org/apache/servicecomb/authentication/AuthenticationServerMain.java @@ -19,7 +19,7 @@ package org.apache.servicecomb.authentication; import org.apache.servicecomb.foundation.common.utils.BeanUtils; -public class AuthenticationServer { +public class AuthenticationServerMain { public static void main(String[] args) { try { BeanUtils.init(); diff --git a/authentication/Client/src/main/java/org/apache/servicecomb/authentication/Client.java b/authentication/Client/src/main/java/org/apache/servicecomb/authentication/AuthenticationClientMain.java similarity index 96% rename from authentication/Client/src/main/java/org/apache/servicecomb/authentication/Client.java rename to authentication/Client/src/main/java/org/apache/servicecomb/authentication/AuthenticationClientMain.java index 4ba1070..ce9c356 100644 --- a/authentication/Client/src/main/java/org/apache/servicecomb/authentication/Client.java +++ b/authentication/Client/src/main/java/org/apache/servicecomb/authentication/AuthenticationClientMain.java @@ -19,7 +19,7 @@ package org.apache.servicecomb.authentication; import org.apache.servicecomb.foundation.common.utils.BeanUtils; -public class Client { +public class AuthenticationClientMain { public static void main(String[] args) { try { BeanUtils.init(); diff --git a/authentication/Client/src/main/java/org/apache/servicecomb/authentication/AuthenticationTestCase.java b/authentication/Client/src/main/java/org/apache/servicecomb/authentication/AuthenticationTestCase.java index 1bae5c3..61ba97f 100644 --- a/authentication/Client/src/main/java/org/apache/servicecomb/authentication/AuthenticationTestCase.java +++ b/authentication/Client/src/main/java/org/apache/servicecomb/authentication/AuthenticationTestCase.java @@ -30,6 +30,12 @@ import org.springframework.web.client.HttpClientErrorException; public class AuthenticationTestCase implements TestCase { @Override public void run() { + testHanlderAuth(); + testMethodAuth(); + } + + + private void testHanlderAuth() { // get token MultiValueMap<String, Object> map = new LinkedMultiValueMap<>(); map.add("userName", "admin"); @@ -75,4 +81,50 @@ public class AuthenticationTestCase implements TestCase { TestMgr.check(null, name); } + + private void testMethodAuth() { + // get token + MultiValueMap<String, Object> map = new LinkedMultiValueMap<>(); + 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", + new HttpEntity<>(map, headers), + Token.class); + TestMgr.check("bearer", token.getToken_type()); + TestMgr.check(true, token.getAccess_token().length() > 10); + + // get resources + headers = new HttpHeaders(); + headers.add("Authorization", "Bearer " + token.getAccess_token()); + headers.setContentType(MediaType.APPLICATION_JSON); + String name; + name = BootEventListener.resouceServerMethodAuthEndpoint.postForObject("/everyoneSayHello?name=Hi", + new HttpEntity<>(headers), + String.class); + TestMgr.check("Hi", name); + + name = BootEventListener.resouceServerMethodAuthEndpoint.postForObject("/adminSayHello?name=Hi", + new HttpEntity<>(headers), + String.class); + TestMgr.check("Hi", name); + + name = BootEventListener.resouceServerMethodAuthEndpoint.postForObject("/guestOrAdminSayHello?name=Hi", + new HttpEntity<>(headers), + String.class); + TestMgr.check("Hi", name); + + name = null; + try { + name = BootEventListener.resouceServerMethodAuthEndpoint.postForObject("/guestSayHello?name=Hi", + new HttpEntity<>(headers), + String.class); + } catch (HttpClientErrorException e) { + TestMgr.check(403, e.getStatusCode().value()); + } + TestMgr.check(null, name); + } } diff --git a/authentication/Client/src/main/java/org/apache/servicecomb/authentication/BootEventListener.java b/authentication/Client/src/main/java/org/apache/servicecomb/authentication/BootEventListener.java index 2af0a55..5512f8c 100644 --- a/authentication/Client/src/main/java/org/apache/servicecomb/authentication/BootEventListener.java +++ b/authentication/Client/src/main/java/org/apache/servicecomb/authentication/BootEventListener.java @@ -25,6 +25,8 @@ public class BootEventListener implements BootListener { public static GateRestTemplate authenticationServerAuthenticationEndpoint; public static GateRestTemplate gateEndpoint; public static GateRestTemplate resouceServerHandlerAuthEndpoint; + public static GateRestTemplate resouceServerMethodAuthEndpoint; + @Override public void onBootEvent(BootEvent event) { if (EventType.AFTER_REGISTRY.equals(event.getEventType())) { @@ -34,6 +36,8 @@ public class BootEventListener implements BootListener { GateRestTemplate.createEdgeRestTemplate("gateway", null, null).init(); resouceServerHandlerAuthEndpoint = GateRestTemplate.createEdgeRestTemplate("gateway", "resource-server", "HandlerAuthEndpoint").init(); + resouceServerMethodAuthEndpoint = + GateRestTemplate.createEdgeRestTemplate("gateway", "resource-server", "PreMethodAuthEndpoint").init(); } } diff --git a/authentication/Client/src/main/java/org/apache/servicecomb/authentication/TestEndpoint.java b/authentication/Client/src/main/java/org/apache/servicecomb/authentication/TestEndpoint.java index 04c3927..19b0af1 100644 --- a/authentication/Client/src/main/java/org/apache/servicecomb/authentication/TestEndpoint.java +++ b/authentication/Client/src/main/java/org/apache/servicecomb/authentication/TestEndpoint.java @@ -29,19 +29,23 @@ import org.springframework.web.bind.annotation.RequestMapping; public class TestEndpoint { @Autowired private List<TestCase> tests; - + @GetMapping(path = "/start") public String start() { tests.forEach(test -> test.run()); - + List<Throwable> errors = TestMgr.errors(); - if (errors.isEmpty()) { - return "success"; + if (TestMgr.isSuccess()) { + return TestMgr.successMessage(); } else { + TestMgr.summary(); + StringBuilder sb = new StringBuilder(); sb.append("Failed count : " + errors.size()); sb.append("\n"); errors.forEach(t -> sb.append(t.getMessage() + "\n")); + + TestMgr.reset(); return sb.toString(); } } diff --git a/authentication/Client/src/main/java/org/apache/servicecomb/authentication/TestMgr.java b/authentication/Client/src/main/java/org/apache/servicecomb/authentication/TestMgr.java index 6b53045..030bb4c 100644 --- a/authentication/Client/src/main/java/org/apache/servicecomb/authentication/TestMgr.java +++ b/authentication/Client/src/main/java/org/apache/servicecomb/authentication/TestMgr.java @@ -19,6 +19,7 @@ package org.apache.servicecomb.authentication; import java.util.ArrayList; import java.util.List; +import java.util.concurrent.atomic.AtomicLong; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -31,6 +32,8 @@ public class TestMgr { private static String msg = ""; + private static AtomicLong checksCount = new AtomicLong(); + public static void setMsg(String msg) { TestMgr.msg = msg; } @@ -44,6 +47,7 @@ public class TestMgr { } public static void check(Object expect, Object real, Throwable error) { + checksCount.incrementAndGet(); if (expect == real) { return; } @@ -90,6 +94,15 @@ public class TestMgr { } } + public static void reset() { + errorList.clear(); + checksCount.set(0); + } + + public static String successMessage() { + return "Success. Checkes = " + checksCount.get(); + } + public static List<Throwable> errors() { return errorList; } diff --git a/authentication/Gateway/src/main/java/org/apache/servicecomb/authentication/gateway/GatewayMain.java b/authentication/Gateway/src/main/java/org/apache/servicecomb/authentication/gateway/AuthenticationGatewayMain.java similarity index 96% rename from authentication/Gateway/src/main/java/org/apache/servicecomb/authentication/gateway/GatewayMain.java rename to authentication/Gateway/src/main/java/org/apache/servicecomb/authentication/gateway/AuthenticationGatewayMain.java index 862e6c3..be15a24 100644 --- a/authentication/Gateway/src/main/java/org/apache/servicecomb/authentication/gateway/GatewayMain.java +++ b/authentication/Gateway/src/main/java/org/apache/servicecomb/authentication/gateway/AuthenticationGatewayMain.java @@ -19,7 +19,7 @@ package org.apache.servicecomb.authentication.gateway; import org.apache.servicecomb.foundation.common.utils.BeanUtils; -public class GatewayMain { +public class AuthenticationGatewayMain { public static void main(String[] args) throws Exception { BeanUtils.init(); } diff --git a/authentication/ResourceServer/src/main/java/org/apache/servicecomb/authentication/ResourceServer.java b/authentication/ResourceServer/src/main/java/org/apache/servicecomb/authentication/ResourceServerMain.java similarity index 96% rename from authentication/ResourceServer/src/main/java/org/apache/servicecomb/authentication/ResourceServer.java rename to authentication/ResourceServer/src/main/java/org/apache/servicecomb/authentication/ResourceServerMain.java index f2653ab..5aae72f 100644 --- a/authentication/ResourceServer/src/main/java/org/apache/servicecomb/authentication/ResourceServer.java +++ b/authentication/ResourceServer/src/main/java/org/apache/servicecomb/authentication/ResourceServerMain.java @@ -19,7 +19,7 @@ package org.apache.servicecomb.authentication; import org.apache.servicecomb.foundation.common.utils.BeanUtils; -public class ResourceServer { +public class ResourceServerMain { public static void main(String[] args) { try { BeanUtils.init(); diff --git a/authentication/ResourceServer/src/main/java/org/apache/servicecomb/authentication/resource/AccessDeniedExceptionExceptionToProducerResponseConverter.java b/authentication/ResourceServer/src/main/java/org/apache/servicecomb/authentication/resource/AccessDeniedExceptionExceptionToProducerResponseConverter.java new file mode 100644 index 0000000..c2decce --- /dev/null +++ b/authentication/ResourceServer/src/main/java/org/apache/servicecomb/authentication/resource/AccessDeniedExceptionExceptionToProducerResponseConverter.java @@ -0,0 +1,39 @@ +/* + * 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.resource; + +import org.apache.servicecomb.swagger.invocation.Response; +import org.apache.servicecomb.swagger.invocation.SwaggerInvocation; +import org.apache.servicecomb.swagger.invocation.exception.ExceptionToProducerResponseConverter; +import org.apache.servicecomb.swagger.invocation.exception.InvocationException; +import org.springframework.security.access.AccessDeniedException; + +public class AccessDeniedExceptionExceptionToProducerResponseConverter + implements ExceptionToProducerResponseConverter<AccessDeniedException> { + + @Override + public Class<AccessDeniedException> getExceptionClass() { + return AccessDeniedException.class; + } + + @Override + public Response convert(SwaggerInvocation swaggerInvocation, AccessDeniedException e) { + return Response.failResp(new InvocationException(403, "forbidden", "not authenticated")); + } + +} diff --git a/authentication/ResourceServer/src/main/java/org/apache/servicecomb/authentication/resource/MethodSecurityConfiguration.java b/authentication/ResourceServer/src/main/java/org/apache/servicecomb/authentication/resource/MethodSecurityConfiguration.java new file mode 100644 index 0000000..58df6a9 --- /dev/null +++ b/authentication/ResourceServer/src/main/java/org/apache/servicecomb/authentication/resource/MethodSecurityConfiguration.java @@ -0,0 +1,36 @@ +/* + * 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.resource; + +import org.springframework.context.annotation.Configuration; +import org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler; +import org.springframework.security.access.expression.method.MethodSecurityExpressionHandler; +import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; +import org.springframework.security.config.annotation.method.configuration.GlobalMethodSecurityConfiguration; + +@Configuration +@EnableGlobalMethodSecurity( + prePostEnabled = true) +public class MethodSecurityConfiguration extends GlobalMethodSecurityConfiguration { + @Override + protected MethodSecurityExpressionHandler createExpressionHandler() { + DefaultMethodSecurityExpressionHandler h = (DefaultMethodSecurityExpressionHandler) super.createExpressionHandler(); + h.setDefaultRolePrefix(""); + return h; + } +} diff --git a/authentication/ResourceServer/src/main/java/org/apache/servicecomb/authentication/resource/PreMethodAuthEndpoint.java b/authentication/ResourceServer/src/main/java/org/apache/servicecomb/authentication/resource/PreMethodAuthEndpoint.java index e07745b..668f774 100644 --- a/authentication/ResourceServer/src/main/java/org/apache/servicecomb/authentication/resource/PreMethodAuthEndpoint.java +++ b/authentication/ResourceServer/src/main/java/org/apache/servicecomb/authentication/resource/PreMethodAuthEndpoint.java @@ -38,7 +38,7 @@ public class PreMethodAuthEndpoint { } @PostMapping(path = "/guestOrAdminSayHello") - @PreAuthorize("hasRole('USER,ADMIN')") + @PreAuthorize("hasAnyRole('USER','ADMIN')") public String guestOrAdminSayHello(String name) { return name; } diff --git a/authentication/ResourceServer/src/main/java/org/apache/servicecomb/authentication/resource/ResourceAuthHandler.java b/authentication/ResourceServer/src/main/java/org/apache/servicecomb/authentication/resource/ResourceAuthHandler.java index 800e52d..37de72d 100644 --- a/authentication/ResourceServer/src/main/java/org/apache/servicecomb/authentication/resource/ResourceAuthHandler.java +++ b/authentication/ResourceServer/src/main/java/org/apache/servicecomb/authentication/resource/ResourceAuthHandler.java @@ -17,6 +17,7 @@ package org.apache.servicecomb.authentication.resource; +import java.util.HashSet; import java.util.Set; import org.apache.commons.lang3.StringUtils; @@ -28,6 +29,12 @@ import org.apache.servicecomb.core.Invocation; import org.apache.servicecomb.foundation.common.utils.BeanUtils; import org.apache.servicecomb.swagger.invocation.AsyncResponse; import org.apache.servicecomb.swagger.invocation.exception.InvocationException; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.authority.SimpleGrantedAuthority; +import org.springframework.security.core.context.SecurityContext; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.core.context.SecurityContextImpl; import org.springframework.security.jwt.Jwt; import org.springframework.security.jwt.JwtHelper; @@ -80,7 +87,14 @@ public class ResourceAuthHandler implements Handler { } // pre method authentiation - invocation.addLocalContext(Constants.CONTEXT_HEADER_CLAIMS, jwt.getClaims()); + Set<GrantedAuthority> grantedAuthorities = new HashSet<>(claims.getAuthorities().size()); + claims.getAuthorities().forEach(v -> grantedAuthorities.add(new SimpleGrantedAuthority(v))); + SecurityContext sc = new SecurityContextImpl(); + Authentication authentication = new SimpleAuthentication(true, grantedAuthorities); + sc.setAuthentication(authentication); + SecurityContextHolder.setContext(sc); + + // next invocation.next(asyncResponse); } diff --git a/authentication/ResourceServer/src/main/java/org/apache/servicecomb/authentication/resource/SimpleAuthentication.java b/authentication/ResourceServer/src/main/java/org/apache/servicecomb/authentication/resource/SimpleAuthentication.java new file mode 100644 index 0000000..a23404c --- /dev/null +++ b/authentication/ResourceServer/src/main/java/org/apache/servicecomb/authentication/resource/SimpleAuthentication.java @@ -0,0 +1,77 @@ +/* + * 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.resource; + +import java.util.Collection; + +import org.springframework.security.core.Authentication; +import org.springframework.security.core.GrantedAuthority; + +public class SimpleAuthentication implements Authentication { + + /** + * + */ + private static final long serialVersionUID = 6077733273349249822L; + + private boolean authenticated; + + private Collection<? extends GrantedAuthority> authorities; + + public SimpleAuthentication(boolean authenticated, Collection<? extends GrantedAuthority> authorities) { + this.authenticated = authenticated; + this.authorities = authorities; + } + + + @Override + public String getName() { + throw new UnsupportedOperationException(); + } + + @Override + public Collection<? extends GrantedAuthority> getAuthorities() { + return this.authorities; + } + + @Override + public Object getCredentials() { + throw new UnsupportedOperationException(); + } + + @Override + public Object getDetails() { + throw new UnsupportedOperationException(); + } + + @Override + public Object getPrincipal() { + throw new UnsupportedOperationException(); + } + + @Override + public boolean isAuthenticated() { + return this.authenticated; + } + + @Override + public void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException { + throw new UnsupportedOperationException(); + } + +} diff --git a/authentication/ResourceServer/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.invocation.exception.ExceptionToProducerResponseConverter b/authentication/ResourceServer/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.invocation.exception.ExceptionToProducerResponseConverter new file mode 100644 index 0000000..e6ad477 --- /dev/null +++ b/authentication/ResourceServer/src/main/resources/META-INF/services/org.apache.servicecomb.swagger.invocation.exception.ExceptionToProducerResponseConverter @@ -0,0 +1,18 @@ +# +# 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. +# + +org.apache.servicecomb.authentication.resource.AccessDeniedExceptionExceptionToProducerResponseConverter \ No newline at end of file
