diff --git a/server/dist/src/main/resources/concord-server.conf b/server/dist/src/main/resources/concord-server.conf
index fe0db4b7fb..e7b0b231ed 100644
--- a/server/dist/src/main/resources/concord-server.conf
+++ b/server/dist/src/main/resources/concord-server.conf
@@ -533,6 +533,17 @@ concord-server {
pfed {
enabled = false
priority = 0
+
+ bearerToken {
+ # enable bearer tokens
+ enableBearerTokens = false
+
+ # allow all clientIds
+ allowAllClientIds = false
+
+ # list of allowed pingfed clientids for bearer tokens
+ allowedClientIds = ["clientId1", "clientId2"]
+ }
}
authEndpointUrl = "http://auth.example.com/authorize"
tokenEndpointUrl = "http://auth.example.com/token"
@@ -549,7 +560,7 @@ concord-server {
# enable to validate token signature
tokenSignatureValidation = false
-
+
# JSON as a string
#tokenEncryptionKey = "{}"
diff --git a/server/plugins/pfed-sso/src/main/java/com/walmartlabs/concord/server/plugins/pfedsso/JwtAuthenticator.java b/server/plugins/pfed-sso/src/main/java/com/walmartlabs/concord/server/plugins/pfedsso/JwtAuthenticator.java
index 754400733f..63753fee7a 100644
--- a/server/plugins/pfed-sso/src/main/java/com/walmartlabs/concord/server/plugins/pfedsso/JwtAuthenticator.java
+++ b/server/plugins/pfed-sso/src/main/java/com/walmartlabs/concord/server/plugins/pfedsso/JwtAuthenticator.java
@@ -39,6 +39,8 @@
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
+import java.util.List;
+
public class JwtAuthenticator {
@@ -78,8 +80,8 @@ public JwtAuthenticator(SsoConfiguration cfg, SsoClient ssoClient) {
* @param token the JWT
* @return true
if token valid and not expired
*/
- public boolean isTokenValid(String token) {
- return isTokenValid(token, null);
+ public boolean isTokenValid(String token, boolean restrictOnClientId) {
+ return isTokenValid(token, null, restrictOnClientId);
}
/**
@@ -89,13 +91,22 @@ public boolean isTokenValid(String token) {
* @param nonce nonce
* @return true
if token valid, correct nonce and not expired
*/
- public boolean isTokenValid(String token, String nonce) {
+ public boolean isTokenValid(String token, String nonce, boolean restrictOnClientId) {
try {
Map claims = validateTokenAndGetClaims(token);
if (claims == null) {
return false;
}
+ if (restrictOnClientId) {
+ List allowedClientIds = cfg.getAllowedClientIds();
+ String clientId = (String) claims.get("client_id");
+ if(!allowedClientIds.contains(clientId)) {
+ log.warn("isTokenValid ['{}', '{}'] -> clientId not in allowed list for bearer tokens", token, clientId);
+ return false;
+ }
+ }
+
if (nonce == null) {
return true;
}
@@ -113,22 +124,7 @@ public boolean isTokenValid(String token, String nonce) {
}
}
- /**
- * Validates the token and returns the corresponding user login.
- *
- * @param token the JWT
- * @return corresponding user login or null
if the JWT is invalid
- */
- public String validateTokenAndGetLogin(String token) {
- Map claims = validateTokenAndGetClaims(token);
- if (claims == null) {
- return null;
- }
- return (String) claims.get("sub");
- }
-
- private Map validateTokenAndGetClaims(String token) {
-
+ public Map validateTokenAndGetClaims(String token) {
try {
JWT jwt = validateToken(token);
if (jwt == null) {
diff --git a/server/plugins/pfed-sso/src/main/java/com/walmartlabs/concord/server/plugins/pfedsso/SsoAuthFilter.java b/server/plugins/pfed-sso/src/main/java/com/walmartlabs/concord/server/plugins/pfedsso/SsoAuthFilter.java
index 2d9051dee6..ddc7c13e1f 100644
--- a/server/plugins/pfed-sso/src/main/java/com/walmartlabs/concord/server/plugins/pfedsso/SsoAuthFilter.java
+++ b/server/plugins/pfed-sso/src/main/java/com/walmartlabs/concord/server/plugins/pfedsso/SsoAuthFilter.java
@@ -66,7 +66,7 @@ public void doFilter(HttpServletRequest request, HttpServletResponse response, F
if (token != null) {
if (refreshToken == null){
- boolean isValid = jwtAuthenticator.isTokenValid(token);
+ boolean isValid = jwtAuthenticator.isTokenValid(token, false);
if (isValid) {
log.info("doFilter -> found valid token in cookies, redirect to '{}'", from);
redirectHelper.sendRedirect(response, from);
diff --git a/server/plugins/pfed-sso/src/main/java/com/walmartlabs/concord/server/plugins/pfedsso/SsoClient.java b/server/plugins/pfed-sso/src/main/java/com/walmartlabs/concord/server/plugins/pfedsso/SsoClient.java
index 5e4f83dc82..f07a303527 100644
--- a/server/plugins/pfed-sso/src/main/java/com/walmartlabs/concord/server/plugins/pfedsso/SsoClient.java
+++ b/server/plugins/pfed-sso/src/main/java/com/walmartlabs/concord/server/plugins/pfedsso/SsoClient.java
@@ -126,9 +126,9 @@ public String getTokenSigningKey() throws IOException {
}
}
- public Profile getUserProfile(String refreshToken) throws IOException {
+ public Profile getUserProfileByRefreshToken(String refreshToken) throws IOException {
Token token = getTokenByRefreshToken(refreshToken);
- return getProfile(token);
+ return getProfile(token.accessToken());
}
private Token getToken(String urlParameters) throws IOException {
@@ -178,7 +178,7 @@ private void postRequest(HttpURLConnection con, String urlParameters) throws IOE
}
}
- private Profile getProfile(Token token) throws IOException {
+ public Profile getProfile(String accessToken) throws IOException {
if (cfg.getUserInfoEndpointUrl() == null) {
return null;
}
@@ -186,7 +186,7 @@ private Profile getProfile(Token token) throws IOException {
try {
URL url = new URL(cfg.getUserInfoEndpointUrl());
con = (HttpURLConnection) url.openConnection();
- String authzHeaderValue = String.format("Bearer %s", token.accessToken());
+ String authzHeaderValue = String.format("Bearer %s", accessToken);
con.setRequestProperty(HttpHeaders.AUTHORIZATION, authzHeaderValue);
con.setRequestProperty(HttpHeaders.CONTENT_TYPE, CONTENT_TYPE_HEADER);
con.setRequestMethod("GET");
@@ -240,6 +240,9 @@ public interface Token {
@JsonIgnoreProperties(ignoreUnknown = true)
public interface Profile {
+ @JsonProperty("sub")
+ String sub();
+
@JsonProperty("sAMAccountName")
String userId();
diff --git a/server/plugins/pfed-sso/src/main/java/com/walmartlabs/concord/server/plugins/pfedsso/SsoConfiguration.java b/server/plugins/pfed-sso/src/main/java/com/walmartlabs/concord/server/plugins/pfedsso/SsoConfiguration.java
index 2514ccc426..880e3fce09 100644
--- a/server/plugins/pfed-sso/src/main/java/com/walmartlabs/concord/server/plugins/pfedsso/SsoConfiguration.java
+++ b/server/plugins/pfed-sso/src/main/java/com/walmartlabs/concord/server/plugins/pfedsso/SsoConfiguration.java
@@ -26,6 +26,10 @@
import javax.inject.Inject;
import java.io.Serializable;
import java.time.Duration;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
public class SsoConfiguration implements Serializable {
@@ -63,6 +67,14 @@ public class SsoConfiguration implements Serializable {
@Config("sso.clientSecret")
private String clientSecret;
+ @Inject
+ @Config("sso.pfed.bearerToken.enableBearerTokens")
+ private boolean enableBearerTokens;
+
+ @Inject
+ @Config("sso.pfed.bearerToken.allowAllClientIds")
+ private boolean allowAllClientIds;
+
@Inject
@Nullable
@Config("sso.tokenSigningKey")
@@ -103,6 +115,10 @@ public class SsoConfiguration implements Serializable {
@Config("sso.autoCreateUsers")
private boolean autoCreateUsers;
+ @Inject
+ @Config("sso.pfed.bearerToken.allowedClientIds")
+ private List allowedClientIds;
+
public boolean isAutoCreateUsers() {
return autoCreateUsers;
}
@@ -135,6 +151,14 @@ public String getClientSecret() {
return clientSecret;
}
+ public boolean getEnableBearerTokens() {
+ return enableBearerTokens;
+ }
+
+ public boolean getAllowAllClientIds() {
+ return allowAllClientIds;
+ }
+
public String getTokenEncryptionKey() {
return tokenEncryptionKey;
}
@@ -170,4 +194,9 @@ public boolean isTokenSignatureValidation() {
public String getUserInfoEndpointUrl() {
return userInfoEndpointUrl;
}
+
+ public List getAllowedClientIds() {
+ return allowedClientIds;
+ }
+
}
diff --git a/server/plugins/pfed-sso/src/main/java/com/walmartlabs/concord/server/plugins/pfedsso/SsoHandler.java b/server/plugins/pfed-sso/src/main/java/com/walmartlabs/concord/server/plugins/pfedsso/SsoHandler.java
index f7aaa47d2a..a7136495ae 100644
--- a/server/plugins/pfed-sso/src/main/java/com/walmartlabs/concord/server/plugins/pfedsso/SsoHandler.java
+++ b/server/plugins/pfed-sso/src/main/java/com/walmartlabs/concord/server/plugins/pfedsso/SsoHandler.java
@@ -56,30 +56,34 @@ public AuthenticationToken createToken(ServletRequest request, ServletResponse r
HttpServletRequest req = WebUtils.toHttp(request);
- String token = SsoCookies.getTokenCookie(req);
+ String bearerToken = cfg.getEnableBearerTokens() ? extractTokenFromRequest(req) : null;
+ String token = bearerToken != null ? bearerToken : SsoCookies.getTokenCookie(req);
+
if (token == null) {
return null;
}
- String login = jwtAuthenticator.validateTokenAndGetLogin(token);
- if (login == null) {
+ boolean restrictOnClientId = (bearerToken != null) && (!cfg.getAllowAllClientIds());
+
+ if (!jwtAuthenticator.isTokenValid(token, restrictOnClientId)) {
return null;
}
- String[] as = parseDomain(login);
-
- String refreshToken = SsoCookies.getRefreshCookie(req);
- // get userprofile send the response as null if refreshToken is expired or used
- SsoClient.Profile profile;
try {
- profile = ssoClient.getUserProfile(refreshToken);
+ SsoClient.Profile profile = bearerToken != null ? ssoClient.getProfile(bearerToken) :
+ ssoClient.getUserProfileByRefreshToken(SsoCookies.getRefreshCookie(req));
+
+ if (profile == null) {
+ return null;
+ }
+
+ String[] as = parseDomain(profile.sub());
+
+ return new SsoToken(as[0], as[1], profile.displayName(), profile.mail(), profile.userPrincipalName(), profile.nameInNamespace(), profile.groups());
+
} catch (IOException e) {
return null;
}
- if (profile == null) {
- return null;
- }
- return new SsoToken(as[0], as[1], profile.displayName(), profile.mail(), profile.userPrincipalName(), profile.nameInNamespace(), profile.groups());
}
@Override
@@ -112,4 +116,20 @@ private String[] parseDomain(String s) {
String domain = s.substring(pos + 1);
return new String[]{username, domain};
}
+
+ private String extractTokenFromRequest(HttpServletRequest request) {
+ final String value = request.getHeader("Authorization");
+
+ if (value == null || !value.toLowerCase().startsWith("bearer")) {
+ return null;
+ }
+
+ String[] parts = value.split(" ");
+
+ if (parts.length < 2) {
+ return null;
+ }
+
+ return parts[1].trim();
+ }
}