use of io.cdap.cdap.proto.security.Credential in project cdap by caskdata.
the class AuthenticationHandler method channelRead.
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
if (!(msg instanceof HttpRequest)) {
ctx.fireChannelRead(msg);
return;
}
HttpRequest request = (HttpRequest) msg;
// Pass if security is bypassed or it has valid access token, process to the next handler
if (isBypassed(request)) {
ctx.fireChannelRead(msg);
return;
}
UserIdentityExtractionResponse extractionResponse = userIdentityExtractor.extract(request);
if (extractionResponse.success()) {
UserIdentityPair userIdentityPair = extractionResponse.getIdentityPair();
// User identity extraction succeeded, so set some header properties and allow the call through
request.headers().remove(HttpHeaderNames.AUTHORIZATION);
Credential credential = getUserCredential(userIdentityPair);
// For backwards compatibility, we continue propagating credentials by default. This may change in the future.
if (cConf.getBoolean(Constants.Security.Authentication.PROPAGATE_USER_CREDENTIAL, true) && credential != null) {
request.headers().set(Constants.Security.Headers.RUNTIME_TOKEN, String.format("%s %s", credential.getType().getQualifiedName(), credential.getValue()));
}
request.headers().set(Constants.Security.Headers.USER_ID, userIdentityPair.getUserIdentity().getUsername());
String clientIP = Networks.getIP(ctx.channel().remoteAddress());
if (clientIP != null) {
request.headers().set(Constants.Security.Headers.USER_IP, clientIP);
}
ctx.fireChannelRead(msg);
return;
}
// Response with failure, plus optionally audit log
try {
HttpHeaders headers = new DefaultHttpHeaders();
JsonObject jsonObject = new JsonObject();
if (extractionResponse.getState().equals(UserIdentityExtractionState.ERROR_MISSING_CREDENTIAL)) {
headers.add(HttpHeaderNames.WWW_AUTHENTICATE, String.format("Bearer realm=\"%s\"", realm));
LOG.debug("Authentication failed due to missing credentials");
} else {
String shortError = extractionResponse.getState().toString();
String errorDescription = extractionResponse.getErrorDescription();
headers.add(HttpHeaderNames.WWW_AUTHENTICATE, String.format("Bearer realm=\"%s\" error=\"%s\" error_description=\"%s\"", realm, shortError, errorDescription));
jsonObject.addProperty("error", shortError);
jsonObject.addProperty("error_description", errorDescription);
LOG.debug("Authentication failed due to error {}, reason={};", shortError, errorDescription);
}
jsonObject.add("auth_uri", getAuthenticationURLs());
ByteBuf content = Unpooled.copiedBuffer(jsonObject.toString(), StandardCharsets.UTF_8);
HttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.UNAUTHORIZED, content);
HttpUtil.setContentLength(response, content.readableBytes());
HttpUtil.setKeepAlive(response, false);
response.headers().setAll(headers);
response.headers().set(HttpHeaderNames.CONTENT_TYPE, "application/json;charset=UTF-8");
auditLogIfNeeded(request, response, ctx.channel());
ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE);
} finally {
ReferenceCountUtil.release(msg);
}
}
use of io.cdap.cdap.proto.security.Credential in project cdap by caskdata.
the class AuthenticationHandler method getUserCredential.
/**
* Get user credential from {@link UserIdentityPair} and return it in encrypted form if enabled.
*/
@Nullable
private Credential getUserCredential(UserIdentityPair userIdentityPair) throws CipherException {
String userCredential = userIdentityPair.getUserCredential();
if (userCredential == null || !sConf.getBoolean(Constants.Security.Authentication.USER_CREDENTIAL_ENCRYPTION_ENABLED, false)) {
return new Credential(userCredential, Credential.CredentialType.EXTERNAL);
}
String encryptedCredential = new TinkCipher(sConf).encryptStringToBase64(userCredential, null);
return new Credential(encryptedCredential, Credential.CredentialType.EXTERNAL_ENCRYPTED);
}
use of io.cdap.cdap.proto.security.Credential in project cdap by caskdata.
the class RemoteClient method setHeader.
private Multimap<String, String> setHeader(HttpRequest request) throws IOException {
Multimap<String, String> headers = request.getHeaders();
headers = headers == null ? HashMultimap.create() : HashMultimap.create(headers);
// Add Authorization header and use a rewritten URL if needed
if (remoteAuthenticator != null && headers.keySet().stream().noneMatch(HttpHeaders.AUTHORIZATION::equalsIgnoreCase)) {
Credential credential = remoteAuthenticator.getCredentials();
if (credential != null) {
setAuthHeader(headers::put, HttpHeaders.AUTHORIZATION, credential.getType().getQualifiedName(), credential.getValue());
}
}
internalAuthenticator.applyInternalAuthenticationHeaders(headers::put);
return headers;
}
use of io.cdap.cdap.proto.security.Credential in project cdap by caskdata.
the class AuthenticationChannelHandler method channelRead.
/**
* Decode the AccessTokenIdentifier passed as a header and set it in a ThreadLocal.
* Returns a 401 if the identifier is malformed.
*/
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
SecurityRequestContext.reset();
// is fixed since we may perform auth checks in the thread processing the last chunk.
if (msg instanceof HttpRequest) {
String currentUserID = null;
Credential currentUserCredential = null;
String currentUserIP = null;
if (internalAuthEnabled) {
// When internal auth is enabled, all requests should typically have user id and credential
// associated with them, for instance, end user credential for user originated ones and
// internal system credential for system originated requests. If there is none, set
// default empty user id and credential.
currentUserID = EMPTY_USER_ID;
currentUserCredential = EMPTY_USER_CREDENTIAL;
currentUserIP = EMPTY_USER_IP;
}
// TODO: authenticate the user using user id - CDAP-688
HttpRequest request = (HttpRequest) msg;
String userID = request.headers().get(Constants.Security.Headers.USER_ID);
if (userID != null) {
currentUserID = userID;
}
String userIP = request.headers().get(Constants.Security.Headers.USER_IP);
if (userIP != null) {
currentUserIP = userIP;
}
String authHeader = request.headers().get(Constants.Security.Headers.RUNTIME_TOKEN);
if (authHeader != null) {
int idx = authHeader.trim().indexOf(' ');
if (idx < 0) {
LOG.error("Invalid Authorization header format for {}@{}", currentUserID, currentUserIP);
if (internalAuthEnabled) {
throw new IllegalArgumentException("Invalid Authorization header format");
}
} else {
String credentialTypeStr = authHeader.substring(0, idx);
try {
Credential.CredentialType credentialType = Credential.CredentialType.fromQualifiedName(credentialTypeStr);
String credentialValue = authHeader.substring(idx + 1).trim();
currentUserCredential = new Credential(credentialValue, credentialType);
SecurityRequestContext.setUserCredential(currentUserCredential);
} catch (IllegalArgumentException e) {
LOG.error("Invalid credential type in Authorization header: {}", credentialTypeStr);
throw e;
}
}
}
LOG.trace("Got user ID '{}' user IP '{}' from IP '{}' and authorization header length '{}'", userID, userIP, ctx.channel().remoteAddress(), authHeader == null ? "NULL" : authHeader.length());
SecurityRequestContext.setUserId(currentUserID);
SecurityRequestContext.setUserCredential(currentUserCredential);
SecurityRequestContext.setUserIP(currentUserIP);
}
try {
ctx.fireChannelRead(msg);
} finally {
SecurityRequestContext.reset();
}
}
use of io.cdap.cdap.proto.security.Credential in project cdap by caskdata.
the class DefaultPreviewRequestQueueTest method testPreviewRequestQueue.
@Test
public void testPreviewRequestQueue() {
PreviewConfig previewConfig = new PreviewConfig("WordCount", ProgramType.WORKFLOW, null, null);
AppRequest<?> testRequest = new AppRequest<>(new ArtifactSummary("test", "1.0"), null, previewConfig);
byte[] pollerInfo = Bytes.toBytes("runner-1");
Optional<PreviewRequest> requestOptional = previewRequestQueue.poll(pollerInfo);
Assert.assertFalse(requestOptional.isPresent());
ApplicationId app1 = new ApplicationId("default", RunIds.generate().getId());
PreviewRequest request = new PreviewRequest(app1, testRequest, null);
previewRequestQueue.add(request);
requestOptional = previewRequestQueue.poll(pollerInfo);
Assert.assertTrue(requestOptional.isPresent());
request = requestOptional.get();
ProgramId programId1 = new ProgramId(app1, ProgramType.WORKFLOW, "WordCount");
Assert.assertEquals(programId1, request.getProgram());
Principal principal = new Principal("userFoo", Principal.PrincipalType.USER, new Credential("userFooCredential", Credential.CredentialType.EXTERNAL));
PreviewRequest requestWithPrinciple = new PreviewRequest(app1, testRequest, principal);
previewRequestQueue.add(requestWithPrinciple);
requestOptional = previewRequestQueue.poll(pollerInfo);
Assert.assertTrue(requestOptional.isPresent());
request = requestOptional.get();
Assert.assertTrue(request.getPrincipal().equals(principal));
requestOptional = previewRequestQueue.poll(pollerInfo);
Assert.assertFalse(requestOptional.isPresent());
ApplicationId app2 = new ApplicationId("default", RunIds.generate().getId());
request = new PreviewRequest(app2, testRequest, null);
previewRequestQueue.add(request);
Assert.assertEquals(0, previewRequestQueue.positionOf(app2));
ApplicationId app3 = new ApplicationId("default", RunIds.generate().getId());
request = new PreviewRequest(app3, testRequest, null);
previewRequestQueue.add(request);
Assert.assertEquals(1, previewRequestQueue.positionOf(app3));
ApplicationId app4 = new ApplicationId("default", RunIds.generate().getId());
request = new PreviewRequest(app4, testRequest, null);
boolean exceptionThrown = false;
try {
previewRequestQueue.add(request);
} catch (IllegalStateException e) {
exceptionThrown = true;
}
Assert.assertTrue(exceptionThrown);
requestOptional = previewRequestQueue.poll(pollerInfo);
Assert.assertTrue(requestOptional.isPresent());
request = requestOptional.get();
ProgramId programId2 = new ProgramId(app2, ProgramType.WORKFLOW, "WordCount");
Assert.assertEquals(programId2, request.getProgram());
requestOptional = previewRequestQueue.poll(pollerInfo);
Assert.assertTrue(requestOptional.isPresent());
request = requestOptional.get();
ProgramId programId3 = new ProgramId(app3, ProgramType.WORKFLOW, "WordCount");
Assert.assertEquals(programId3, request.getProgram());
requestOptional = previewRequestQueue.poll(pollerInfo);
Assert.assertFalse(requestOptional.isPresent());
}
Aggregations