Skip to content

Commit bb398b1

Browse files
committed
Implement client credential and on-behalf-of flow validators; update flavor handling in authorization
1 parent e12af7e commit bb398b1

6 files changed

Lines changed: 104 additions & 11 deletions

File tree

api-project/src/main/java/org/opendevstack/apiservice/project/util/SecurityUtils.java

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,22 @@ private SecurityUtils() {
1313
}
1414

1515
public static UUID getClientId() {
16-
String appId = null;
1716
Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
1817

1918
if (principal instanceof Jwt) {
20-
appId = ((Jwt) principal).getClaimAsString("appid");
19+
Jwt jwt = ((Jwt) principal);
20+
String clientId = jwt.getClaimAsString("azp");
21+
if (clientId == null || clientId.isBlank()) {
22+
clientId = jwt.getClaimAsString("appid");
23+
}
24+
25+
if (clientId == null || clientId.isBlank()) {
26+
throw new InvalidBearerTokenException("Client ID not found in token claims");
27+
}
28+
29+
return UUID.fromString(clientId);
2130
} else {
2231
throw new InvalidBearerTokenException("Invalid authentication token: " + principal.getClass().getName());
2332
}
24-
25-
return UUID.fromString(appId);
2633
}
2734
}

core-security/src/main/java/org/opendevstack/apiservice/core/security/authorization/PolicyAuthorizationManager.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,10 @@ public org.springframework.security.authorization.AuthorizationDecision check(
5151

5252
Optional<ApiDefinition> apiDef = this.resolver.resolve(request);
5353

54+
if (apiDef.isPresent()) {
55+
request.setAttribute("oas.apiDefinition", apiDef.get());
56+
}
57+
5458
// Unknown routes are denied (fail-closed). Public API definitions are allowed.
5559
if (apiDef.isEmpty()) {
5660
return new org.springframework.security.authorization.AuthorizationDecision(false);

core-security/src/main/java/org/opendevstack/apiservice/core/security/authorization/evaluator/FlavorRestrictionEvaluator.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ public AuthorizationDecision evaluate(PolicyContext context) {
3737
return AuthorizationDecision.ABSTAIN;
3838
}
3939

40-
String requestedFlavor = (String) body.get("flavor");
40+
String requestedFlavor = (String) body.get("projectFlavor");
4141
if (requestedFlavor == null) {
4242
return AuthorizationDecision.ABSTAIN;
4343
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
package org.opendevstack.apiservice.core.security.flow.validator;
2+
3+
import org.opendevstack.apiservice.core.contracts.auth.AuthType;
4+
import org.opendevstack.apiservice.core.security.flow.AuthFlowValidator;
5+
import org.springframework.security.oauth2.jwt.Jwt;
6+
import org.springframework.stereotype.Component;
7+
8+
@Component
9+
public class ClientCredentialFlowValidator implements AuthFlowValidator {
10+
11+
@Override
12+
public AuthType getSupportedFlow() {
13+
return AuthType.CLIENT_CREDENTIALS;
14+
}
15+
16+
@Override
17+
public boolean validate(Jwt jwt) {
18+
String appid = jwt.getClaimAsString("appid");
19+
if (appid == null || appid.isBlank()) {
20+
return false;
21+
}
22+
23+
Object aud = jwt.getClaim("aud");
24+
if (aud == null) {
25+
return false;
26+
}
27+
28+
String scp = jwt.getClaimAsString("scp");
29+
if (scp != null && !scp.isBlank()) {
30+
return false;
31+
}
32+
33+
String upn = jwt.getClaimAsString("upn");
34+
String preferredUsername = jwt.getClaimAsString("preferred_username");
35+
if ((upn != null && !upn.isBlank()) || (preferredUsername != null && !preferredUsername.isBlank())) {
36+
return false;
37+
}
38+
39+
String sub = jwt.getSubject();
40+
String oid = jwt.getClaimAsString("oid");
41+
if (sub == null || oid == null || !sub.equals(oid)) {
42+
return false;
43+
}
44+
45+
return true;
46+
}
47+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
package org.opendevstack.apiservice.core.security.flow.validator;
2+
3+
import org.opendevstack.apiservice.core.contracts.auth.AuthType;
4+
import org.opendevstack.apiservice.core.security.flow.AuthFlowValidator;
5+
import org.springframework.security.oauth2.jwt.Jwt;
6+
import org.springframework.stereotype.Component;
7+
8+
@Component
9+
public class OboFlowValidator implements AuthFlowValidator {
10+
11+
@Override
12+
public AuthType getSupportedFlow() {
13+
return AuthType.OBO;
14+
}
15+
16+
@Override
17+
public boolean validate(Jwt jwt) {
18+
String scp = jwt.getClaimAsString("scp");
19+
if (scp == null || scp.isBlank()) {
20+
return false;
21+
}
22+
23+
String roles = jwt.getClaimAsString("roles");
24+
if (roles != null && !roles.isBlank()) {
25+
return false;
26+
}
27+
28+
String user = jwt.getClaimAsString("upn");
29+
if (user == null || user.isBlank()) {
30+
user = jwt.getClaimAsString("preferred_username");
31+
}
32+
33+
if (user == null || user.isBlank()) {
34+
user = jwt.getSubject();
35+
}
36+
37+
return user != null && !user.isBlank();
38+
}
39+
40+
}

core/pom.xml

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -145,12 +145,7 @@
145145
<artifactId>api-project-platform</artifactId>
146146
<version>${project.version}</version>
147147
</dependency>
148-
149-
<dependency>
150-
<groupId>org.opendevstack.apiservice</groupId>
151-
<artifactId>api-project-component-v0</artifactId>
152-
<version>${project.version}</version>
153-
</dependency>
148+
154149
<!-- Service Projects module: project creation and key generation -->
155150
<dependency>
156151
<groupId>org.opendevstack.apiservice</groupId>

0 commit comments

Comments
 (0)