Skip to content

Commit

Permalink
Merge pull request #15691 from cdapio/internal-router-cdf
Browse files Browse the repository at this point in the history
[CDAP-21062] Propagate internal credentials in Router
  • Loading branch information
adrikagupta authored Aug 29, 2024
2 parents f5f8cb5 + 5170923 commit fd59e3b
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
import com.google.inject.Inject;
import io.cdap.cdap.common.conf.CConfiguration;
import io.cdap.cdap.common.conf.Constants;
import io.cdap.cdap.proto.security.Credential;
import io.cdap.cdap.security.auth.UserIdentity.IdentifierType;
import io.netty.handler.codec.http.HttpHeaderNames;
import io.netty.handler.codec.http.HttpRequest;
import java.util.LinkedHashSet;
Expand All @@ -45,7 +47,7 @@ public ProxyUserIdentityExtractor(CConfiguration cConf) {
/**
* Extracts the user identity from the HTTP request.
*
* Expects the user's credential to be in the Authorization header in "Bearer" form. Expects the
* <p>Expects the user's credential to be in the Authorization header in "Bearer" form. Expects the
* user's identity to be in the configuration-specified header.
*
* @param request The HTTP Request to extract the user identity from
Expand All @@ -68,19 +70,30 @@ public UserIdentityExtractionResponse extract(HttpRequest request)
UserIdentity identity = new UserIdentity(userIdentity, UserIdentity.IdentifierType.EXTERNAL,
new LinkedHashSet<>(), now, now + EXPIRATION_SECS);

// Parse the access token from authorization header. The header will be in "Bearer" form.
// Parse the access token from authorization header. The header will be in
// {@link io.cdap.cdap.proto.security.Credential.CredentialType#EXTERNAL_BEARER} form, if external
// or {@link io.cdap.cdap.proto.security.Credential.CredentialType#INTERNAL} if internal
String auth = request.headers().get(HttpHeaderNames.AUTHORIZATION);
LOG.trace("Extracted user identity header '{}' and authorization header length '{}'",
userIdentity,
auth == null ? "NULL" : String.valueOf(auth.length()));
String userCredential = null;
String prefix = "";
if (auth != null) {
int idx = auth.trim().indexOf(' ');
if (idx < 0) {
return new UserIdentityExtractionResponse(new UserIdentityPair(null, identity));
}
prefix = auth.substring(0, idx).trim();
userCredential = auth.substring(idx + 1).trim();
}

if (Credential.CREDENTIAL_TYPE_INTERNAL.equalsIgnoreCase(prefix)) {
UserIdentity internalIdentity = new UserIdentity(userIdentity, IdentifierType.INTERNAL,
new LinkedHashSet<>(), now, now + EXPIRATION_SECS);
return new UserIdentityExtractionResponse(new UserIdentityPair(userCredential, internalIdentity));
}

return new UserIdentityExtractionResponse(new UserIdentityPair(userCredential, identity));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

import io.cdap.cdap.common.conf.CConfiguration;
import io.cdap.cdap.common.conf.Constants;
import io.cdap.cdap.security.auth.UserIdentity.IdentifierType;
import io.netty.handler.codec.http.DefaultHttpHeaders;
import io.netty.handler.codec.http.DefaultHttpRequest;
import io.netty.handler.codec.http.HttpHeaderNames;
Expand Down Expand Up @@ -90,6 +91,30 @@ public void testValidUserReturnsExpectedIdentity() throws UserIdentityExtraction
Assert.assertEquals(testUserId, identity.getUserIdentity().getUsername());
}

@Test
public void testValidInternalUserReturnsExpectedInternalIdentity() throws UserIdentityExtractionException {
String testUserId = "test-user-id";
String testUserIdHeader = "X-User-Id";
String testAuthToken = "test-auth-token";
CConfiguration config = Mockito.mock(CConfiguration.class);
when(config.get(Constants.Security.Authentication.PROXY_USER_ID_HEADER)).thenReturn(testUserIdHeader);

ProxyUserIdentityExtractor extractor = new ProxyUserIdentityExtractor(config);

DefaultHttpHeaders headers = new DefaultHttpHeaders();
headers.add(HttpHeaderNames.AUTHORIZATION, String.format("CDAP-Internal %s", testAuthToken));
headers.add(testUserIdHeader, testUserId);
DefaultHttpRequest request = new DefaultHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET,
"http://www.example.com", headers);
UserIdentityExtractionResponse response = extractor.extract(request);
Assert.assertTrue(response.success());
UserIdentityPair identity = response.getIdentityPair();

Assert.assertEquals(testAuthToken, identity.getUserCredential());
Assert.assertEquals(testUserId, identity.getUserIdentity().getUsername());
Assert.assertEquals(identity.getUserIdentity().getIdentifierType(), IdentifierType.INTERNAL);
}

@Test
public void testValidUserWithoutCredentialReturnsExpectedIdentity() throws UserIdentityExtractionException {
String testUserId = "test-user-id";
Expand Down

0 comments on commit fd59e3b

Please sign in to comment.