-
Notifications
You must be signed in to change notification settings - Fork 36
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
CASSSIDECAR-161: Add RBAC Authorization support in Sidecar (#165)
Patch by Saranya Krishnakumar, Raymond Welgosh; reviewed by Bernardo Botella, Venkata Harikrishna Nukala, Yifan Cai, Francisco Guerrero for CASSSIDECAR-161 Co-authored-by: Raymond Welgosh <[email protected]> Co-authored-by: Saranya Krishnakumar <[email protected]>
- Loading branch information
Showing
83 changed files
with
4,326 additions
and
418 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
63 changes: 63 additions & 0 deletions
63
...r/src/main/java/org/apache/cassandra/sidecar/acl/authorization/AdminIdentityResolver.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
/* | ||
* 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.cassandra.sidecar.acl.authorization; | ||
|
||
import java.util.Set; | ||
|
||
import com.google.inject.Inject; | ||
import com.google.inject.Singleton; | ||
import org.apache.cassandra.sidecar.acl.IdentityToRoleCache; | ||
import org.apache.cassandra.sidecar.config.SidecarConfiguration; | ||
|
||
/** | ||
* Evaluates if provided identity is an admin identity. | ||
*/ | ||
@Singleton | ||
public class AdminIdentityResolver | ||
{ | ||
private final IdentityToRoleCache identityToRoleCache; | ||
private final SuperUserCache superUserCache; | ||
private final Set<String> adminIdentities; | ||
|
||
@Inject | ||
public AdminIdentityResolver(IdentityToRoleCache identityToRoleCache, | ||
SuperUserCache superUserCache, | ||
SidecarConfiguration sidecarConfiguration) | ||
{ | ||
this.identityToRoleCache = identityToRoleCache; | ||
this.superUserCache = superUserCache; | ||
this.adminIdentities = sidecarConfiguration.accessControlConfiguration().adminIdentities(); | ||
} | ||
|
||
public boolean isAdmin(String identity) | ||
{ | ||
if (adminIdentities.contains(identity)) | ||
{ | ||
return true; | ||
} | ||
|
||
String role = identityToRoleCache.get(identity); | ||
if (role == null) | ||
{ | ||
return false; | ||
} | ||
// Cassandra superusers have admin privileges | ||
return superUserCache.isSuperUser(role); | ||
} | ||
} |
81 changes: 81 additions & 0 deletions
81
...in/java/org/apache/cassandra/sidecar/acl/authorization/AllowAllAuthorizationProvider.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
/* | ||
* 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.cassandra.sidecar.acl.authorization; | ||
|
||
import io.vertx.core.AsyncResult; | ||
import io.vertx.core.Future; | ||
import io.vertx.core.Handler; | ||
import io.vertx.ext.auth.User; | ||
import io.vertx.ext.auth.authorization.Authorization; | ||
import io.vertx.ext.auth.authorization.AuthorizationContext; | ||
import io.vertx.ext.auth.authorization.AuthorizationProvider; | ||
|
||
/** | ||
* {@link AuthorizationProvider} implementation to allow all requests regardless of authorizations user holds. | ||
*/ | ||
public class AllowAllAuthorizationProvider implements AuthorizationProvider | ||
{ | ||
final Authorization authorization; | ||
|
||
public AllowAllAuthorizationProvider() | ||
{ | ||
// Authorization that always allows | ||
authorization = new Authorization() | ||
{ | ||
@Override | ||
public boolean match(AuthorizationContext context) | ||
{ | ||
return true; | ||
} | ||
|
||
@Override | ||
public boolean verify(Authorization authorization) | ||
{ | ||
return true; | ||
} | ||
}; | ||
} | ||
|
||
/** | ||
* @return unique id representing {@code AllowAllAuthorizationProvider} | ||
*/ | ||
@Override | ||
public String getId() | ||
{ | ||
return "AllowAll"; | ||
} | ||
|
||
@Override | ||
public void getAuthorizations(User user, Handler<AsyncResult<Void>> handler) | ||
{ | ||
getAuthorizations(user).onComplete(handler); | ||
} | ||
|
||
@Override | ||
public Future<Void> getAuthorizations(User user) | ||
{ | ||
if (user == null) | ||
{ | ||
return Future.failedFuture("User cannot be null"); | ||
} | ||
|
||
user.authorizations().add(getId(), authorization); | ||
return Future.succeededFuture(); | ||
} | ||
} |
83 changes: 83 additions & 0 deletions
83
...org/apache/cassandra/sidecar/acl/authorization/AuthorizationParameterValidateHandler.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
/* | ||
* 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.cassandra.sidecar.acl.authorization; | ||
|
||
import com.google.inject.Inject; | ||
import com.google.inject.Singleton; | ||
import io.vertx.core.http.HttpServerRequest; | ||
import io.vertx.core.net.SocketAddress; | ||
import io.vertx.ext.web.RoutingContext; | ||
import org.apache.cassandra.sidecar.common.server.data.Name; | ||
import org.apache.cassandra.sidecar.common.server.data.QualifiedTableName; | ||
import org.apache.cassandra.sidecar.concurrent.ExecutorPools; | ||
import org.apache.cassandra.sidecar.routes.AbstractHandler; | ||
import org.apache.cassandra.sidecar.routes.RoutingContextUtils; | ||
import org.apache.cassandra.sidecar.snapshots.SnapshotPathBuilder; | ||
import org.apache.cassandra.sidecar.utils.CassandraInputValidator; | ||
import org.apache.cassandra.sidecar.utils.InstanceMetadataFetcher; | ||
|
||
/** | ||
* Simple handler that extracts authorization parameters keyspace/table parameters from the path, validates them, | ||
* and then adds them to the context. | ||
*/ | ||
@Singleton | ||
public class AuthorizationParameterValidateHandler extends AbstractHandler<QualifiedTableName> | ||
{ | ||
private final SnapshotPathBuilder snapshotPathBuilder; | ||
|
||
/** | ||
* Constructs a handler with the provided {@code metadataFetcher} | ||
* | ||
* @param metadataFetcher the interface to retrieve instance metadata | ||
* @param executorPools the executor pools for blocking executions | ||
* @param validator a validator instance to validate Cassandra-specific input | ||
*/ | ||
@Inject | ||
protected AuthorizationParameterValidateHandler(InstanceMetadataFetcher metadataFetcher, | ||
ExecutorPools executorPools, | ||
CassandraInputValidator validator, | ||
SnapshotPathBuilder snapshotPathBuilder) | ||
{ | ||
super(metadataFetcher, executorPools, validator); | ||
this.snapshotPathBuilder = snapshotPathBuilder; | ||
} | ||
|
||
@Override | ||
protected void handleInternal(RoutingContext context, | ||
HttpServerRequest httpRequest, | ||
String host, | ||
SocketAddress remoteAddress, | ||
QualifiedTableName qualifiedTableName) | ||
{ | ||
RoutingContextUtils.put(context, RoutingContextUtils.SC_QUALIFIED_TABLE_NAME, qualifiedTableName); | ||
} | ||
|
||
@Override | ||
protected QualifiedTableName extractParamsOrThrow(RoutingContext context) | ||
{ | ||
Name tableName = null; | ||
String tableNameParam = context.pathParam(TABLE_PATH_PARAM); | ||
if (tableNameParam != null) | ||
{ | ||
// Remove the tableId for routes that have the tableId as part of the path parameter | ||
tableName = validator.validateTableName(snapshotPathBuilder.maybeRemoveTableId(tableNameParam)); | ||
} | ||
return new QualifiedTableName(keyspace(context, false), tableName); | ||
} | ||
} |
72 changes: 72 additions & 0 deletions
72
...a/org/apache/cassandra/sidecar/acl/authorization/AuthorizationWithAdminBypassHandler.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
/* | ||
* 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.cassandra.sidecar.acl.authorization; | ||
|
||
import java.util.List; | ||
|
||
import io.netty.handler.codec.http.HttpResponseStatus; | ||
import io.vertx.ext.auth.authorization.Authorization; | ||
import io.vertx.ext.web.RoutingContext; | ||
import io.vertx.ext.web.handler.HttpException; | ||
import io.vertx.ext.web.handler.impl.AuthorizationHandlerImpl; | ||
|
||
import static org.apache.cassandra.sidecar.utils.AuthUtils.extractIdentities; | ||
|
||
/** | ||
* Verifies user has required authorizations. Allows admin identities to bypass authorization checks. | ||
*/ | ||
public class AuthorizationWithAdminBypassHandler extends AuthorizationHandlerImpl | ||
{ | ||
private final AuthorizationParameterValidateHandler authZParameterValidateHandler; | ||
private final AdminIdentityResolver adminIdentityResolver; | ||
|
||
public AuthorizationWithAdminBypassHandler(AuthorizationParameterValidateHandler authZParameterValidateHandler, | ||
AdminIdentityResolver adminIdentityResolver, | ||
Authorization authorization) | ||
{ | ||
super(authorization); | ||
this.authZParameterValidateHandler = authZParameterValidateHandler; | ||
this.adminIdentityResolver = adminIdentityResolver; | ||
} | ||
|
||
@Override | ||
public void handle(RoutingContext ctx) | ||
{ | ||
authZParameterValidateHandler.handle(ctx); | ||
if (ctx.failed()) // failed due to validation | ||
{ | ||
return; | ||
} | ||
|
||
List<String> identities = extractIdentities(ctx.user()); | ||
if (identities.isEmpty()) | ||
{ | ||
throw new HttpException(HttpResponseStatus.FORBIDDEN.code(), "Client identities are missing"); | ||
} | ||
|
||
// Admin identities bypass route specific authorization checks | ||
if (identities.stream().anyMatch(adminIdentityResolver::isAdmin)) | ||
{ | ||
ctx.next(); | ||
return; | ||
} | ||
|
||
super.handle(ctx); | ||
} | ||
} |
Oops, something went wrong.