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/07/08 07:35:48 UTC
[servicecomb-fence] 01/02: [SCB-1350]support third party
authentications
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 bb5731ddb1ffcb534cda5f7ac9df215c04c05565
Author: liubao <bi...@qq.com>
AuthorDate: Fri Jul 5 16:42:37 2019 +0800
[SCB-1350]support third party authentications
---
.../server/GithubAccessTokenResponse.java} | 37 ++++--
.../authentication/server/GithubAuthService.java} | 31 ++---
.../server/GithubDynamicProperties.java | 60 ++++++++++
.../server/GithubDynamicPropertiesManager.java} | 26 ++--
.../authentication/server/GithubTokenGranter.java | 133 +++++++++++++++++++++
.../server/ThirdPartyProviderEndpoint.java | 55 +++++++++
.../server/ThirdPartyRegisterBootListener.java | 46 +++++++
.../server/ThirdPartyTokenGranter.java | 58 +++++++++
.../server/AuthenticationServerConstants.java | 22 +++-
.../server/ThirdPartyProviderService.java} | 27 ++---
.../authentication/token/JWTTokenImpl.java | 5 +
.../authentication/token/OpenIDToken.java | 5 +
.../authentication/token/SessionTokenImpl.java | 14 ++-
.../servicecomb/authentication/token/Token.java | 2 +
.../AuthenticationConfiguration.java | 9 ++
.../src/main/resources/microservice.yaml | 5 +
.../src/main/resources/ui/githubLoginCallback.html | 103 ++++++++++++++++
.../EdgeService/src/main/resources/ui/js/login.js | 55 +++++++++
.../EdgeService/src/main/resources/ui/login.html | 8 ++
19 files changed, 635 insertions(+), 66 deletions(-)
diff --git a/api/common/service/src/main/java/org/apache/servicecomb/authentication/token/Token.java b/api/authentication-server/endpoint/src/main/java/org/apache/servicecomb/authentication/server/GithubAccessTokenResponse.java
similarity index 54%
copy from api/common/service/src/main/java/org/apache/servicecomb/authentication/token/Token.java
copy to api/authentication-server/endpoint/src/main/java/org/apache/servicecomb/authentication/server/GithubAccessTokenResponse.java
index 1f444c3..03bb9c5 100644
--- a/api/common/service/src/main/java/org/apache/servicecomb/authentication/token/Token.java
+++ b/api/authentication-server/endpoint/src/main/java/org/apache/servicecomb/authentication/server/GithubAccessTokenResponse.java
@@ -14,26 +14,39 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+package org.apache.servicecomb.authentication.server;
-package org.apache.servicecomb.authentication.token;
+// see: https://developer.github.com/apps/building-oauth-apps/authorizing-oauth-apps/
+public class GithubAccessTokenResponse {
+ private String access_token;
-import java.util.Map;
+ private String scope;
-public interface Token {
- String username();
+ private String token_type;
- default boolean isExpired() {
- return (System.currentTimeMillis() < getNotBefore()) ||
- (System.currentTimeMillis() - getIssueAt() > getExpiresIn() * 1000);
+ public String getAccess_token() {
+ return access_token;
}
- long getIssueAt();
+ public void setAccess_token(String access_token) {
+ this.access_token = access_token;
+ }
+
+ public String getScope() {
+ return scope;
+ }
- long getExpiresIn();
+ public void setScope(String scope) {
+ this.scope = scope;
+ }
- long getNotBefore();
+ public String getToken_type() {
+ return token_type;
+ }
+
+ public void setToken_type(String token_type) {
+ this.token_type = token_type;
+ }
- String getValue();
- Map<String, Object> getAdditionalInformation();
}
diff --git a/api/authentication-server/service/src/main/java/org/apache/servicecomb/authentication/server/AuthenticationServerConstants.java b/api/authentication-server/endpoint/src/main/java/org/apache/servicecomb/authentication/server/GithubAuthService.java
similarity index 53%
copy from api/authentication-server/service/src/main/java/org/apache/servicecomb/authentication/server/AuthenticationServerConstants.java
copy to api/authentication-server/endpoint/src/main/java/org/apache/servicecomb/authentication/server/GithubAuthService.java
index 193e6d8..08ebe4e 100644
--- a/api/authentication-server/service/src/main/java/org/apache/servicecomb/authentication/server/AuthenticationServerConstants.java
+++ b/api/authentication-server/endpoint/src/main/java/org/apache/servicecomb/authentication/server/GithubAuthService.java
@@ -17,22 +17,23 @@
package org.apache.servicecomb.authentication.server;
-public class AuthenticationServerConstants {
- public static final String PARAM_GRANT_TYPE = "grant_type";
+import javax.ws.rs.FormParam;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
- public static final String PARAM_USERNAME = "username";
+import org.springframework.http.MediaType;
- public static final String PARAM_PASSWORD = "password";
+import io.swagger.annotations.Api;
- public static final String PARAM_REFRESH_TOKEN = "refresh_token";
-
- public static final String PARAM_ACCESS_TOKEN = "access_token";
-
- public static final String GRANT_TYPE_PASSWORD = "password";
-
- public static final String GRANT_TYPE_REFRESH_TOKEN = "refresh_token";
-
- public static final String CONFIG_GRANTER_PASSWORD_ENABLED = "servicecomb.authentication.granter.password.enabled";
-
- public static final String CONFIG_GRANTER_REFRESH_TOKEN_ENABLED = "servicecomb.authentication.granter.refreshToken.enabled";
+//see: https://developer.github.com/apps/building-oauth-apps/authorizing-oauth-apps/
+@Path("/login/oauth")
+@Api(produces = MediaType.APPLICATION_JSON_VALUE)
+public interface GithubAuthService {
+ @POST
+ @Path("/access_token")
+ public GithubAccessTokenResponse accessToken(@FormParam("client_id") String client_id,
+ @FormParam("client_secret") String client_secret,
+ @FormParam("code") String code,
+ @FormParam("state") String state,
+ @FormParam("redirect_uri") String redirect_uri);
}
diff --git a/api/authentication-server/endpoint/src/main/java/org/apache/servicecomb/authentication/server/GithubDynamicProperties.java b/api/authentication-server/endpoint/src/main/java/org/apache/servicecomb/authentication/server/GithubDynamicProperties.java
new file mode 100644
index 0000000..c61f0a7
--- /dev/null
+++ b/api/authentication-server/endpoint/src/main/java/org/apache/servicecomb/authentication/server/GithubDynamicProperties.java
@@ -0,0 +1,60 @@
+/*
+ * 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.server;
+
+import org.apache.servicecomb.config.inject.InjectProperties;
+import org.apache.servicecomb.config.inject.InjectProperty;
+
+@InjectProperties(prefix = "servicecomb.authentication.github")
+public class GithubDynamicProperties {
+ @InjectProperty(keys = "clientId")
+ private String clientId;
+
+ // TODO : support secret encryption
+ @InjectProperty(keys = "clientSecret")
+ private String clientSecret;
+
+ @InjectProperty(keys = "oauthAuthorizeURL", defaultValue = "https://github.com/login/oauth/authorize")
+ private String oauthAuthorizeURL;
+
+ public String getClientId() {
+ return clientId;
+ }
+
+ public void setClientId(String clientId) {
+ this.clientId = clientId;
+ }
+
+ public String getClientSecret() {
+ return clientSecret;
+ }
+
+ public void setClientSecret(String clientSecret) {
+ this.clientSecret = clientSecret;
+ }
+
+ public String getOauthAuthorizeURL() {
+ return oauthAuthorizeURL;
+ }
+
+ public void setOauthAuthorizeURL(String oauthAuthorizeURL) {
+ this.oauthAuthorizeURL = oauthAuthorizeURL;
+ }
+
+
+}
diff --git a/api/common/service/src/main/java/org/apache/servicecomb/authentication/token/Token.java b/api/authentication-server/endpoint/src/main/java/org/apache/servicecomb/authentication/server/GithubDynamicPropertiesManager.java
similarity index 57%
copy from api/common/service/src/main/java/org/apache/servicecomb/authentication/token/Token.java
copy to api/authentication-server/endpoint/src/main/java/org/apache/servicecomb/authentication/server/GithubDynamicPropertiesManager.java
index 1f444c3..69e5f6f 100644
--- a/api/common/service/src/main/java/org/apache/servicecomb/authentication/token/Token.java
+++ b/api/authentication-server/endpoint/src/main/java/org/apache/servicecomb/authentication/server/GithubDynamicPropertiesManager.java
@@ -15,25 +15,21 @@
* limitations under the License.
*/
-package org.apache.servicecomb.authentication.token;
+package org.apache.servicecomb.authentication.server;
import java.util.Map;
-public interface Token {
- String username();
+import org.apache.servicecomb.config.inject.ConfigObjectFactory;
+import org.apache.servicecomb.foundation.common.concurrent.ConcurrentHashMapEx;
- default boolean isExpired() {
- return (System.currentTimeMillis() < getNotBefore()) ||
- (System.currentTimeMillis() - getIssueAt() > getExpiresIn() * 1000);
- }
-
- long getIssueAt();
-
- long getExpiresIn();
+public class GithubDynamicPropertiesManager {
+ private static final Map<String, GithubDynamicProperties> CONFIGURATIONS = new ConcurrentHashMapEx<>();
- long getNotBefore();
+ private static final ConfigObjectFactory FACTORY = new ConfigObjectFactory();
- String getValue();
-
- Map<String, Object> getAdditionalInformation();
+ public static GithubDynamicProperties getGithubConfiguration() {
+ return CONFIGURATIONS.computeIfAbsent("key", key -> {
+ return FACTORY.create(GithubDynamicProperties.class);
+ });
+ }
}
diff --git a/api/authentication-server/endpoint/src/main/java/org/apache/servicecomb/authentication/server/GithubTokenGranter.java b/api/authentication-server/endpoint/src/main/java/org/apache/servicecomb/authentication/server/GithubTokenGranter.java
new file mode 100644
index 0000000..4c372e6
--- /dev/null
+++ b/api/authentication-server/endpoint/src/main/java/org/apache/servicecomb/authentication/server/GithubTokenGranter.java
@@ -0,0 +1,133 @@
+/*
+ * 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.server;
+
+import java.io.UnsupportedEncodingException;
+
+import org.apache.commons.lang3.StringUtils;
+import org.apache.servicecomb.authentication.token.AbstractOpenIDTokenStore;
+import org.apache.servicecomb.authentication.token.OpenIDToken;
+import org.apache.servicecomb.authentication.util.CommonConstants;
+import org.apache.servicecomb.provider.pojo.RpcReference;
+import org.apache.servicecomb.provider.springmvc.reference.RestTemplateBuilder;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.http.HttpEntity;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.MediaType;
+import org.springframework.security.core.userdetails.UserDetails;
+import org.springframework.security.core.userdetails.UserDetailsService;
+import org.springframework.security.core.userdetails.UsernameNotFoundException;
+import org.springframework.stereotype.Component;
+import org.springframework.util.LinkedMultiValueMap;
+import org.springframework.util.MultiValueMap;
+import org.springframework.web.client.RestTemplate;
+import org.springframework.web.util.UriUtils;
+
+import com.netflix.config.DynamicPropertyFactory;
+
+@Component
+public class GithubTokenGranter implements ThirdPartyTokenGranter {
+ private static final Logger LOGGER = LoggerFactory.getLogger(GithubTokenGranter.class);
+
+ @Autowired
+ @Qualifier(CommonConstants.BEAN_AUTH_USER_DETAILS_SERVICE)
+ private UserDetailsService userDetailsService;
+
+ @Autowired
+ @Qualifier(CommonConstants.BEAN_AUTH_OPEN_ID_TOKEN_STORE)
+ private AbstractOpenIDTokenStore openIDTokenStore;
+
+ @RpcReference(microserviceName = "githubAuthService", schemaId = "githubAuthService")
+ GithubAuthService githubAuthService;
+
+ RestTemplate githubRestTemplate = RestTemplateBuilder.create();
+
+ @Override
+ public boolean enabled() {
+ return DynamicPropertyFactory.getInstance()
+ .getBooleanProperty(AuthenticationServerConstants.CONFIG_GRANTER_THIRD_GITHUB_ENABLED, true)
+ .get();
+ }
+
+ @Override
+ public String name() {
+ return AuthenticationServerConstants.GRANT_TYPE_THIRD_PARTY_GITHUB;
+ }
+
+ @Override
+ public TokenResponse grant(String code, String state, String login) {
+ GithubAccessTokenResponse response = null;
+ try {
+ HttpHeaders headers = new HttpHeaders();
+ headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
+ headers.set(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE);
+ MultiValueMap<String, String> map = new LinkedMultiValueMap<>();
+ map.add("client_secret", GithubDynamicPropertiesManager.getGithubConfiguration().getClientSecret());
+ map.add("client_id", GithubDynamicPropertiesManager.getGithubConfiguration().getClientId());
+ map.add("code", code);
+ map.add("state", state);
+ HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<>(map, headers);
+ response = githubRestTemplate.postForObject("cse://githubAuthService/login/oauth/access_token",
+ request,
+ GithubAccessTokenResponse.class);
+ } catch (Exception e) {
+ LOGGER.error("Call github error. ", e);
+ }
+
+ if (StringUtils.isEmpty(login)) {
+ login = "anonymous";
+ }
+ try {
+ UserDetails userDetails = userDetailsService.loadUserByUsername("github:" + login);
+
+ OpenIDToken openIDToken = openIDTokenStore.createToken(userDetails);
+ openIDToken.addAdditionalInformation(AuthenticationServerConstants.TOKEN_ADDTIONAL_INFORMATION_GITHUB_TOKEN,
+ response);
+
+ openIDTokenStore.saveToken(openIDToken);
+ return TokenResponse.fromOpenIDToken(openIDToken);
+ } catch (UsernameNotFoundException e) {
+ return null;
+ }
+ }
+
+ @Override
+ public String providerInfo(String provider, String redirectURI, String login, String scope, String initialState) {
+ StringBuilder url = new StringBuilder();
+ url.append(GithubDynamicPropertiesManager.getGithubConfiguration().getOauthAuthorizeURL() + "?");
+ url.append("client_id=" + GithubDynamicPropertiesManager.getGithubConfiguration().getClientId() + "&");
+ try {
+ if (login != null) {
+ url.append("login=" + UriUtils.encode(login, "utf-8") + "&");
+ redirectURI = redirectURI + "&login=" + login;
+ }
+ if (scope != null) {
+ url.append("scope=" + UriUtils.encode(scope, "utf-8") + "&");
+ }
+ url.append("redirect_uri=" + UriUtils.encode(redirectURI, "utf-8") + "&");
+ } catch (UnsupportedEncodingException e) {
+ // will not happen, ignore
+ }
+ url.append("state=" + initialState);
+ return url.toString();
+ }
+
+}
diff --git a/api/authentication-server/endpoint/src/main/java/org/apache/servicecomb/authentication/server/ThirdPartyProviderEndpoint.java b/api/authentication-server/endpoint/src/main/java/org/apache/servicecomb/authentication/server/ThirdPartyProviderEndpoint.java
new file mode 100644
index 0000000..f8196a3
--- /dev/null
+++ b/api/authentication-server/endpoint/src/main/java/org/apache/servicecomb/authentication/server/ThirdPartyProviderEndpoint.java
@@ -0,0 +1,55 @@
+/*
+ * 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.server;
+
+import java.util.List;
+
+import org.apache.servicecomb.provider.rest.common.RestSchema;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.CookieValue;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+
+@RestSchema(schemaId = "ThirdPartyProviderEndpoint")
+@RequestMapping(path = "/v1/thirdParty")
+public class ThirdPartyProviderEndpoint implements ThirdPartyProviderService {
+ @Autowired
+ private List<ThirdPartyTokenGranter> granters;
+
+ @Override
+ @GetMapping(path = "/providerInfo/{provider}")
+ public String providerInfo(@PathVariable(name = "provider") String provider,
+ @RequestParam(name = "login", required = false) String login,
+ @RequestParam(name = "redirectURI") String redirectURI,
+ @RequestParam(name = "scope", required = false) String scope,
+ @CookieValue(name = "initialState") String initialState) {
+
+ for (ThirdPartyTokenGranter granter : granters) {
+ if (granter.enabled() && granter.name().equals(provider)) {
+ String info = granter.providerInfo(provider, redirectURI, login, scope, initialState);
+ if (info != null) {
+ return info;
+ }
+ }
+ }
+
+ return null;
+ }
+}
diff --git a/api/authentication-server/endpoint/src/main/java/org/apache/servicecomb/authentication/server/ThirdPartyRegisterBootListener.java b/api/authentication-server/endpoint/src/main/java/org/apache/servicecomb/authentication/server/ThirdPartyRegisterBootListener.java
new file mode 100644
index 0000000..e6ec1da
--- /dev/null
+++ b/api/authentication-server/endpoint/src/main/java/org/apache/servicecomb/authentication/server/ThirdPartyRegisterBootListener.java
@@ -0,0 +1,46 @@
+/*
+ * 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.server;
+
+import java.util.Collections;
+
+import org.apache.servicecomb.core.BootListener;
+import org.apache.servicecomb.serviceregistry.RegistryUtils;
+import org.springframework.stereotype.Component;
+
+//see: https://developer.github.com/apps/building-oauth-apps/authorizing-oauth-apps/
+@Component
+public class ThirdPartyRegisterBootListener implements BootListener {
+ private static final String GITHUB_ENDPOINT = "rest://github.com:443?sslEnabled=true";
+
+ @Override
+ public void onBootEvent(BootEvent event) {
+ if (BootListener.EventType.AFTER_REGISTRY.equals(event.getEventType())) {
+ RegistryUtils.getServiceRegistry().registerMicroserviceMappingByEndpoints(
+ // 3rd party rest service name
+ "githubAuthService",
+ // service version
+ "1.0.0",
+ // list of endpoints
+ Collections.singletonList(GITHUB_ENDPOINT),
+ // java interface class to generate swagger schema
+ GithubAuthService.class);
+ }
+ }
+
+}
diff --git a/api/authentication-server/endpoint/src/main/java/org/apache/servicecomb/authentication/server/ThirdPartyTokenGranter.java b/api/authentication-server/endpoint/src/main/java/org/apache/servicecomb/authentication/server/ThirdPartyTokenGranter.java
new file mode 100644
index 0000000..1ef4fc8
--- /dev/null
+++ b/api/authentication-server/endpoint/src/main/java/org/apache/servicecomb/authentication/server/ThirdPartyTokenGranter.java
@@ -0,0 +1,58 @@
+/*
+ * 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.server;
+
+import java.util.Map;
+
+import org.apache.commons.lang3.StringUtils;
+
+public interface ThirdPartyTokenGranter extends TokenGranter {
+
+ @Override
+ default String grantType() {
+ return AuthenticationServerConstants.GRANT_TYPE_THIRD_PARTY;
+ }
+
+ @Override
+ default TokenResponse grant(Map<String, String> parameters) {
+ String provider = parameters.get(AuthenticationServerConstants.PARAM_PROVIDER);
+ String code = parameters.get(AuthenticationServerConstants.PARAM_CODE);
+ String state = parameters.get(AuthenticationServerConstants.PARAM_STATE);
+ String login = parameters.get(AuthenticationServerConstants.PARAM_LOGIN);
+
+ // login can be null
+ if (StringUtils.isEmpty(provider) || StringUtils.isEmpty(code) || StringUtils.isEmpty(state)) {
+ return null;
+ }
+
+ if (!name().equals(provider)) {
+ return null;
+ }
+
+ return grant(code, state, login);
+ }
+
+ String name();
+
+ TokenResponse grant(String code, String state, String login);
+
+ /**
+ * In authorization code mode, need to get authentication provider information first.
+ */
+ String providerInfo(String provider, String redirectURI, String login, String scope, String initialState);
+}
diff --git a/api/authentication-server/service/src/main/java/org/apache/servicecomb/authentication/server/AuthenticationServerConstants.java b/api/authentication-server/service/src/main/java/org/apache/servicecomb/authentication/server/AuthenticationServerConstants.java
index 193e6d8..7b6f219 100644
--- a/api/authentication-server/service/src/main/java/org/apache/servicecomb/authentication/server/AuthenticationServerConstants.java
+++ b/api/authentication-server/service/src/main/java/org/apache/servicecomb/authentication/server/AuthenticationServerConstants.java
@@ -28,11 +28,29 @@ public class AuthenticationServerConstants {
public static final String PARAM_ACCESS_TOKEN = "access_token";
+ public static final String PARAM_PROVIDER = "provider";
+
+ public static final String PARAM_CODE = "code";
+
+ public static final String PARAM_STATE = "state";
+
+ public static final String PARAM_LOGIN = "login";
+
public static final String GRANT_TYPE_PASSWORD = "password";
+
+ public static final String GRANT_TYPE_THIRD_PARTY = "third_party";
+
+ public static final String GRANT_TYPE_THIRD_PARTY_GITHUB = "github";
public static final String GRANT_TYPE_REFRESH_TOKEN = "refresh_token";
-
+
public static final String CONFIG_GRANTER_PASSWORD_ENABLED = "servicecomb.authentication.granter.password.enabled";
+
+ public static final String CONFIG_GRANTER_THIRD_GITHUB_ENABLED =
+ "servicecomb.authentication.granter.thirdParty.github.enabled";
+
+ public static final String CONFIG_GRANTER_REFRESH_TOKEN_ENABLED =
+ "servicecomb.authentication.granter.refreshToken.enabled";
- public static final String CONFIG_GRANTER_REFRESH_TOKEN_ENABLED = "servicecomb.authentication.granter.refreshToken.enabled";
+ public static final String TOKEN_ADDTIONAL_INFORMATION_GITHUB_TOKEN = "github-token";
}
diff --git a/api/common/service/src/main/java/org/apache/servicecomb/authentication/token/Token.java b/api/authentication-server/service/src/main/java/org/apache/servicecomb/authentication/server/ThirdPartyProviderService.java
similarity index 64%
copy from api/common/service/src/main/java/org/apache/servicecomb/authentication/token/Token.java
copy to api/authentication-server/service/src/main/java/org/apache/servicecomb/authentication/server/ThirdPartyProviderService.java
index 1f444c3..55dd29e 100644
--- a/api/common/service/src/main/java/org/apache/servicecomb/authentication/token/Token.java
+++ b/api/authentication-server/service/src/main/java/org/apache/servicecomb/authentication/server/ThirdPartyProviderService.java
@@ -15,25 +15,12 @@
* limitations under the License.
*/
-package org.apache.servicecomb.authentication.token;
+package org.apache.servicecomb.authentication.server;
-import java.util.Map;
-
-public interface Token {
- String username();
-
- default boolean isExpired() {
- return (System.currentTimeMillis() < getNotBefore()) ||
- (System.currentTimeMillis() - getIssueAt() > getExpiresIn() * 1000);
- }
-
- long getIssueAt();
-
- long getExpiresIn();
-
- long getNotBefore();
-
- String getValue();
-
- Map<String, Object> getAdditionalInformation();
+/**
+ * Connecting third party oAuth providers
+ *
+ */
+public interface ThirdPartyProviderService {
+ String providerInfo(String provider, String redirectURI, String login, String scope, String initialState);
}
diff --git a/api/common/service/src/main/java/org/apache/servicecomb/authentication/token/JWTTokenImpl.java b/api/common/service/src/main/java/org/apache/servicecomb/authentication/token/JWTTokenImpl.java
index 980f96e..1c8c133 100644
--- a/api/common/service/src/main/java/org/apache/servicecomb/authentication/token/JWTTokenImpl.java
+++ b/api/common/service/src/main/java/org/apache/servicecomb/authentication/token/JWTTokenImpl.java
@@ -77,4 +77,9 @@ public class JWTTokenImpl implements JWTToken {
public JWTClaims getClaims() {
return this.claims;
}
+
+ @Override
+ public void addAdditionalInformation(String key, Object value) {
+ this.claims.addAdditionalInformation(key, value);
+ }
}
diff --git a/api/common/service/src/main/java/org/apache/servicecomb/authentication/token/OpenIDToken.java b/api/common/service/src/main/java/org/apache/servicecomb/authentication/token/OpenIDToken.java
index 2587619..d82b663 100644
--- a/api/common/service/src/main/java/org/apache/servicecomb/authentication/token/OpenIDToken.java
+++ b/api/common/service/src/main/java/org/apache/servicecomb/authentication/token/OpenIDToken.java
@@ -105,4 +105,9 @@ public class OpenIDToken implements Token {
public Map<String, Object> getAdditionalInformation() {
return accessToken.getAdditionalInformation();
}
+
+ @Override
+ public void addAdditionalInformation(String key, Object value) {
+ accessToken.addAdditionalInformation(key, value);
+ }
}
diff --git a/api/common/service/src/main/java/org/apache/servicecomb/authentication/token/SessionTokenImpl.java b/api/common/service/src/main/java/org/apache/servicecomb/authentication/token/SessionTokenImpl.java
index d31e775..d409ee9 100644
--- a/api/common/service/src/main/java/org/apache/servicecomb/authentication/token/SessionTokenImpl.java
+++ b/api/common/service/src/main/java/org/apache/servicecomb/authentication/token/SessionTokenImpl.java
@@ -17,6 +17,7 @@
package org.apache.servicecomb.authentication.token;
+import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
@@ -29,6 +30,8 @@ public class SessionTokenImpl implements SessionToken {
private TokenDynamicProperties config;
+ private Map<String, Object> additionalInformation;
+
public SessionTokenImpl(String username) {
this.value = UUID.randomUUID().toString();
this.issueAt = System.currentTimeMillis();
@@ -58,12 +61,19 @@ public class SessionTokenImpl implements SessionToken {
@Override
public Map<String, Object> getAdditionalInformation() {
- // TODO additional information is not used now
- return null;
+ return additionalInformation;
}
@Override
public String username() {
return this.username;
}
+
+ @Override
+ public void addAdditionalInformation(String key, Object value) {
+ if (additionalInformation == null) {
+ additionalInformation = new HashMap<>();
+ }
+ additionalInformation.put(key, value);
+ }
}
diff --git a/api/common/service/src/main/java/org/apache/servicecomb/authentication/token/Token.java b/api/common/service/src/main/java/org/apache/servicecomb/authentication/token/Token.java
index 1f444c3..ca51f89 100644
--- a/api/common/service/src/main/java/org/apache/servicecomb/authentication/token/Token.java
+++ b/api/common/service/src/main/java/org/apache/servicecomb/authentication/token/Token.java
@@ -36,4 +36,6 @@ public interface Token {
String getValue();
Map<String, Object> getAdditionalInformation();
+
+ void addAdditionalInformation(String key, Object value);
}
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 992bb33..0921bb6 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
@@ -67,9 +67,18 @@ public class AuthenticationConfiguration {
Arrays.asList(new SimpleGrantedAuthority("GUEST")));
UserDetails uGuestExpiresQuickly = new User("guestExpiresQuickly", passwordEncoder.encode("changeMyPassword"),
Arrays.asList(new SimpleGrantedAuthority("GUEST")));
+
+ // Third party users
+ UserDetails githubAnonymous = new User("github:anonymous", "",
+ Arrays.asList(new SimpleGrantedAuthority("GUEST")));
+ UserDetails githubLiubao68 = new User("github:liubao68", "",
+ Arrays.asList(new SimpleGrantedAuthority("ADMIN")));
+
manager.createUser(uAdmin);
manager.createUser(uGuest);
manager.createUser(uGuestExpiresQuickly);
+ manager.createUser(githubAnonymous);
+ manager.createUser(githubLiubao68);
return manager;
}
}
diff --git a/samples/AuthenticationServer/src/main/resources/microservice.yaml b/samples/AuthenticationServer/src/main/resources/microservice.yaml
index 35ac8bb..2a2373d 100644
--- a/samples/AuthenticationServer/src/main/resources/microservice.yaml
+++ b/samples/AuthenticationServer/src/main/resources/microservice.yaml
@@ -40,3 +40,8 @@ servicecomb:
expiresIn: 600
guestExpiresQuickly:
expiresIn: 3
+
+ github:
+ clientId: ? # change to your github client id
+ clientSecret: ? # change to your github client secret
+
diff --git a/samples/EdgeService/src/main/resources/ui/githubLoginCallback.html b/samples/EdgeService/src/main/resources/ui/githubLoginCallback.html
new file mode 100644
index 0000000..facbf7c
--- /dev/null
+++ b/samples/EdgeService/src/main/resources/ui/githubLoginCallback.html
@@ -0,0 +1,103 @@
+<!DOCTYPE html>
+
+<!--
+ ~ 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.
+ -->
+
+<html>
+
+ <head>
+ <title>Github Login in progress ...</title>
+ <link href="css/style.css" rel="stylesheet" type="text/css" media="all" />
+ <script type="text/javascript" src="js/jquery-1.11.1.min.js"></script>
+ <script type="text/javascript" src="js/login.js"></script>
+
+ <script>
+ var executed = false;
+ (document.onready = function () {
+ if(executed) {
+ return;
+ }
+ executed = true;
+
+ <!-- getting query params -->
+ <!-- -->
+ var match,
+ pl = /\+/g, // Regex for replacing addition symbol with a space
+ search = /([^&=]+)=?([^&]*)/g,
+ decode = function (s) { return decodeURIComponent(s.replace(pl, " ")); },
+ query = window.location.search.substring(1);
+
+ var urlParams = {};
+ while (match = search.exec(query))
+ urlParams[decode(match[1])] = decode(match[2]);
+
+ if(getCookie("initialState") != urlParams["state"]) {
+ window.alert("CSRF attack!");
+ return;
+ }
+
+ if(!urlParams["code"]) {
+ window.alert("Access denied!");
+ return;
+ }
+
+ var formData = {};
+ formData.code = urlParams["code"];
+ formData.state = urlParams["state"];
+ formData.provider = "github";
+ formData.grant_type = "third_party";
+
+ <!-- send code to backgroupd processing -->
+ $.ajax({
+ type: 'POST',
+ url: "/v1/token",
+ data: formData,
+ success: function (data) {
+ console.log(JSON.stringify(data));
+ window.localStorage.setItem("token", JSON.stringify(data));
+ window.location = "/ui/operation.html";
+ },
+ error: function(data) {
+ console.log(JSON.stringify(data));
+ var error = document.getElementById("error");
+ error.textContent="Login failed";
+ error.hidden=false;
+ },
+ async: true
+ });
+ })();
+ </script>
+ </head>
+
+ <body>
+
+ <div class="header">
+ <h2>Login With Github</h2>
+ </div>
+ <div class="section">
+ <form method="POST" enctype="multipart/form-data">
+ <input type="button" value="Login With Github" onclick="loginWithGithubAction()">
+ </form>
+ </div>
+ <div class="footer">
+ <p id="error" hidden="true" class="error"/>
+ </div>
+ </body>
+
+</html>
+
+
diff --git a/samples/EdgeService/src/main/resources/ui/js/login.js b/samples/EdgeService/src/main/resources/ui/js/login.js
index 69c3c9b..b811187 100644
--- a/samples/EdgeService/src/main/resources/ui/js/login.js
+++ b/samples/EdgeService/src/main/resources/ui/js/login.js
@@ -42,3 +42,58 @@ function loginAction() {
});
}
+function loginWithGithubAction() {
+ setCookie("initialState", Math.floor(100000000 + Math.random() * 900000000), 1);
+ var redirectURI = window.location.protocol + "//"
+ + window.location.hostname + ":" + window.location.port
+ + "/ui/githubLoginCallback.html";
+ redirectURI = encodeURIComponent(redirectURI);
+
+ $.ajax({
+ type: 'GET',
+ url: "/api/authentication-server/v1/thirdParty/providerInfo/github?redirectURI=" + redirectURI,
+ success: function (data) {
+ console.log(JSON.stringify(data));
+ window.location = data;
+ },
+ error: function(data) {
+ console.log(JSON.stringify(data));
+ var error = document.getElementById("error");
+ error.textContent="Login failed";
+ error.hidden=false;
+ },
+ async: true
+ });
+}
+
+/*
+* https://www.w3schools.com/js/js_cookies.asp
+*/
+function setCookie(name,value,days) {
+ var expires = "";
+ if (days) {
+ var date = new Date();
+ date.setTime(date.getTime() + (days*24*60*60*1000));
+ expires = "; expires=" + date.toUTCString();
+ }
+ document.cookie = name + "=" + (value || "") + expires + "; path=/";
+}
+
+/*
+* https://www.w3schools.com/js/js_cookies.asp
+*/
+function getCookie(cname) {
+ var name = cname + "=";
+ var decodedCookie = decodeURIComponent(document.cookie);
+ var ca = decodedCookie.split(';');
+ for(var i = 0; i <ca.length; i++) {
+ var c = ca[i];
+ while (c.charAt(0) == ' ') {
+ c = c.substring(1);
+ }
+ if (c.indexOf(name) == 0) {
+ return c.substring(name.length, c.length);
+ }
+ }
+ return "";
+}
\ No newline at end of file
diff --git a/samples/EdgeService/src/main/resources/ui/login.html b/samples/EdgeService/src/main/resources/ui/login.html
index c8b45fb..85e5abe 100644
--- a/samples/EdgeService/src/main/resources/ui/login.html
+++ b/samples/EdgeService/src/main/resources/ui/login.html
@@ -37,6 +37,14 @@
<input type="button" value="Login" onclick="loginAction()">
</form>
</div>
+ <div class="header">
+ <h2>Login With Github</h2>
+ </div>
+ <div class="section">
+ <form method="POST" enctype="multipart/form-data">
+ <input type="button" value="Login With Github" onclick="loginWithGithubAction()">
+ </form>
+ </div>
<div class="footer">
<p id="error" hidden="true" class="error"/>
</div>