├── .dockerignore ├── .gitignore ├── CHANGES.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── VERSION ├── code ├── authorizer │ ├── Dockerfile │ ├── install.sh │ ├── pom.xml │ └── src │ │ ├── main │ │ ├── java │ │ │ └── com │ │ │ │ └── google │ │ │ │ └── cloud │ │ │ │ └── broker │ │ │ │ └── apps │ │ │ │ └── authorizer │ │ │ │ └── Authorizer.java │ │ └── resources │ │ │ ├── index.soy │ │ │ ├── reference.conf │ │ │ ├── server_error.soy │ │ │ └── success.soy │ │ └── test │ │ └── java │ │ └── com │ │ └── google │ │ └── cloud │ │ └── broker │ │ └── apps │ │ └── authorizer │ │ ├── AuthorizerTest.java │ │ └── TemplateTest.java ├── broker-server │ ├── Dockerfile │ ├── descriptor.xml │ ├── install-dev.sh │ ├── install.sh │ ├── pom.xml │ └── src │ │ ├── main │ │ ├── java │ │ │ └── com │ │ │ │ └── google │ │ │ │ └── cloud │ │ │ │ └── broker │ │ │ │ └── apps │ │ │ │ └── brokerserver │ │ │ │ ├── BrokerServer.java │ │ │ │ ├── ClientAddressServerInterceptor.java │ │ │ │ ├── accesstokens │ │ │ │ ├── AccessBoundaryUtils.java │ │ │ │ ├── AccessToken.java │ │ │ │ ├── AccessTokenCacheFetcher.java │ │ │ │ └── providers │ │ │ │ │ ├── AbstractProvider.java │ │ │ │ │ ├── AbstractUserProvider.java │ │ │ │ │ ├── DomainWideDelegationAuthorityProvider.java │ │ │ │ │ ├── HybridProvider.java │ │ │ │ │ ├── RefreshTokenProvider.java │ │ │ │ │ ├── RevokeRefreshTokens.java │ │ │ │ │ ├── ServiceAccountProvider.java │ │ │ │ │ └── experimental │ │ │ │ │ └── JSONFileCredentialsProvider.java │ │ │ │ ├── endpoints │ │ │ │ ├── CancelSessionToken.java │ │ │ │ ├── GetAccessToken.java │ │ │ │ ├── GetSessionToken.java │ │ │ │ └── RenewSessionToken.java │ │ │ │ ├── logging │ │ │ │ ├── CustomJsonLayout.java │ │ │ │ └── LoggingUtils.java │ │ │ │ ├── sessions │ │ │ │ ├── Session.java │ │ │ │ ├── SessionAuthenticator.java │ │ │ │ ├── SessionCacheFetcher.java │ │ │ │ ├── SessionCleanup.java │ │ │ │ ├── SessionToken.java │ │ │ │ └── SessionTokenUtils.java │ │ │ │ └── validation │ │ │ │ ├── GrpcRequestValidation.java │ │ │ │ ├── ProxyUserValidation.java │ │ │ │ └── ScopeValidation.java │ │ ├── proto │ │ │ └── broker.proto │ │ └── resources │ │ │ ├── logback.xml │ │ │ └── reference.conf │ │ └── test │ │ └── java │ │ └── com │ │ └── google │ │ └── cloud │ │ └── broker │ │ ├── apps │ │ └── brokerserver │ │ │ ├── BrokerServerTest.java │ │ │ ├── accesstokens │ │ │ ├── AccessBoundaryUtilsTest.java │ │ │ ├── AccessTokenCacheFetcherTest.java │ │ │ ├── MockAccessBoundary.java │ │ │ └── providers │ │ │ │ ├── AbstractProviderTest.java │ │ │ │ ├── DomainWideDelegationAuthorityProviderTest.java │ │ │ │ ├── HybridProviderTest.java │ │ │ │ ├── MockProvider.java │ │ │ │ ├── RefreshTokenProviderTest.java │ │ │ │ └── ServiceAccountProviderTest.java │ │ │ ├── sessions │ │ │ ├── SessionCacheFetcherTest.java │ │ │ └── SessionTest.java │ │ │ └── validation │ │ │ ├── ProxyUserValidationTest.java │ │ │ └── ValidationTest.java │ │ ├── authentication │ │ └── backends │ │ │ └── MockAuthenticator.java │ │ └── usermapping │ │ └── MockUserMapper.java ├── client │ ├── client-lib │ │ ├── pom.xml │ │ └── src │ │ │ └── main │ │ │ ├── java │ │ │ └── com │ │ │ │ └── google │ │ │ │ └── cloud │ │ │ │ └── broker │ │ │ │ └── client │ │ │ │ ├── connect │ │ │ │ ├── BrokerGateway.java │ │ │ │ └── BrokerServerInfo.java │ │ │ │ ├── credentials │ │ │ │ ├── BrokerBaseCredentials.java │ │ │ │ ├── BrokerKerberosCredentials.java │ │ │ │ └── BrokerSessionCredentials.java │ │ │ │ ├── endpoints │ │ │ │ ├── CancelSessionToken.java │ │ │ │ ├── GetAccessToken.java │ │ │ │ ├── GetSessionToken.java │ │ │ │ └── RenewSessionToken.java │ │ │ │ └── utils │ │ │ │ ├── GrpcUtils.java │ │ │ │ ├── OAuthUtils.java │ │ │ │ └── SpnegoUtils.java │ │ │ └── proto │ │ │ └── broker.proto │ └── hadoop-connector │ │ ├── pom.xml │ │ └── src │ │ ├── main │ │ ├── java │ │ │ └── com │ │ │ │ └── google │ │ │ │ └── cloud │ │ │ │ └── broker │ │ │ │ └── client │ │ │ │ └── hadoop │ │ │ │ └── fs │ │ │ │ ├── BrokerAccessTokenProvider.java │ │ │ │ ├── BrokerDelegationTokenBinding.java │ │ │ │ ├── BrokerTokenIdentifier.java │ │ │ │ ├── BrokerTokenRenewer.java │ │ │ │ ├── Utils.java │ │ │ │ └── commands │ │ │ │ ├── CancelSessionToken.java │ │ │ │ ├── CommandUtils.java │ │ │ │ ├── GetAccessToken.java │ │ │ │ ├── GetSessionToken.java │ │ │ │ ├── PingServer.java │ │ │ │ └── RenewSessionToken.java │ │ └── resources │ │ │ └── META-INF │ │ │ └── services │ │ │ ├── org.apache.hadoop.security.token.TokenIdentifier │ │ │ └── org.apache.hadoop.security.token.TokenRenewer │ │ └── test │ │ └── java │ │ └── com │ │ └── google │ │ └── cloud │ │ └── broker │ │ └── client │ │ ├── hadoop │ │ └── fs │ │ │ ├── BrokerAccessTokenProviderTest.java │ │ │ ├── BrokerDelegationTokenBindingTest.java │ │ │ ├── BrokerTokenIdentifierTest.java │ │ │ └── TestingTools.java │ │ └── utils │ │ ├── GrpcUtilsTest.java │ │ └── SpnegoUtilsTest.java ├── core │ ├── pom.xml │ └── src │ │ ├── main │ │ └── java │ │ │ └── com │ │ │ └── google │ │ │ └── cloud │ │ │ └── broker │ │ │ ├── authentication │ │ │ ├── AuthorizationHeaderServerInterceptor.java │ │ │ └── backends │ │ │ │ ├── AbstractAuthenticationBackend.java │ │ │ │ └── SpnegoAuthenticator.java │ │ │ ├── caching │ │ │ ├── CacheFetcher.java │ │ │ ├── local │ │ │ │ └── LocalCache.java │ │ │ └── remote │ │ │ │ ├── AbstractRemoteCache.java │ │ │ │ └── DummyCache.java │ │ │ ├── checks │ │ │ ├── CheckResult.java │ │ │ └── SystemCheck.java │ │ │ ├── database │ │ │ ├── DatabaseObjectNotFound.java │ │ │ ├── InitializeDatabase.java │ │ │ ├── backends │ │ │ │ ├── AbstractDatabaseBackend.java │ │ │ │ └── DummyDatabaseBackend.java │ │ │ └── models │ │ │ │ └── Model.java │ │ │ ├── encryption │ │ │ └── backends │ │ │ │ ├── AbstractEncryptionBackend.java │ │ │ │ └── DummyEncryptionBackend.java │ │ │ ├── oauth │ │ │ ├── OauthClientSecretsLoader.java │ │ │ ├── RefreshToken.java │ │ │ └── RefreshTokenUtils.java │ │ │ ├── secretmanager │ │ │ ├── DownloadSecrets.java │ │ │ └── SecretManager.java │ │ │ ├── settings │ │ │ └── AppSettings.java │ │ │ ├── usermapping │ │ │ ├── AbstractUserMapper.java │ │ │ ├── KerberosUserMapper.java │ │ │ └── MapUser.java │ │ │ ├── utils │ │ │ ├── CloudStorageUtils.java │ │ │ ├── Constants.java │ │ │ ├── InstanceUtils.java │ │ │ └── TimeUtils.java │ │ │ └── validation │ │ │ └── EmailValidation.java │ │ └── test │ │ └── java │ │ └── com │ │ └── google │ │ └── cloud │ │ └── broker │ │ ├── authentication │ │ └── backends │ │ │ ├── AbstractAuthenticationBackendTest.java │ │ │ ├── FakeKDC.java │ │ │ └── SpnegoAuthenticatorTest.java │ │ ├── caching │ │ └── remote │ │ │ └── AbstractRemoteCacheTest.java │ │ ├── database │ │ └── backends │ │ │ └── AbstractDatabaseBackendTest.java │ │ ├── encryption │ │ └── backends │ │ │ └── AbstractEncryptionBackendTest.java │ │ ├── oauth │ │ └── RefreshTokenTest.java │ │ ├── secretmanager │ │ └── SecretManagerTest.java │ │ ├── settings │ │ └── SettingsOverride.java │ │ └── usermapping │ │ └── KerberosUserMapperTest.java └── extensions │ ├── caching │ ├── cloud-datastore │ │ ├── pom.xml │ │ └── src │ │ │ ├── main │ │ │ └── java │ │ │ │ └── com │ │ │ │ └── google │ │ │ │ └── cloud │ │ │ │ └── broker │ │ │ │ └── caching │ │ │ │ └── remote │ │ │ │ ├── CloudDatastoreCache.java │ │ │ │ └── DatastoreCacheCleanup.java │ │ │ └── test │ │ │ └── java │ │ │ └── com │ │ │ └── google │ │ │ └── cloud │ │ │ └── broker │ │ │ └── caching │ │ │ └── remote │ │ │ └── CloudDatastoreCacheTest.java │ └── redis │ │ ├── pom.xml │ │ └── src │ │ ├── main │ │ └── java │ │ │ └── com │ │ │ └── google │ │ │ └── cloud │ │ │ └── broker │ │ │ └── caching │ │ │ └── remote │ │ │ └── RedisCache.java │ │ └── test │ │ └── java │ │ └── com │ │ └── google │ │ └── cloud │ │ └── broker │ │ └── caching │ │ └── remote │ │ └── RedisCacheTest.java │ ├── database │ ├── cloud-datastore │ │ ├── pom.xml │ │ └── src │ │ │ ├── main │ │ │ └── java │ │ │ │ └── com │ │ │ │ └── google │ │ │ │ └── cloud │ │ │ │ └── broker │ │ │ │ └── database │ │ │ │ └── backends │ │ │ │ └── CloudDatastoreBackend.java │ │ │ └── test │ │ │ └── java │ │ │ └── com │ │ │ └── google │ │ │ └── cloud │ │ │ └── broker │ │ │ └── database │ │ │ └── backends │ │ │ ├── CloudDatastoreBackendTest.java │ │ │ └── Foo.java │ └── jdbc │ │ ├── pom.xml │ │ └── src │ │ ├── main │ │ └── java │ │ │ └── com │ │ │ └── google │ │ │ └── cloud │ │ │ └── broker │ │ │ └── database │ │ │ └── backends │ │ │ └── JDBCBackend.java │ │ └── test │ │ └── java │ │ └── com │ │ └── google │ │ └── cloud │ │ └── broker │ │ └── database │ │ └── backends │ │ ├── JDBCBackendTest.java │ │ ├── MariaDBBackendTest.java │ │ ├── PostgreSQLBackendTest.java │ │ └── SQLiteBackendTest.java │ └── encryption │ └── cloud-kms │ ├── pom.xml │ └── src │ ├── main │ └── java │ │ └── com │ │ └── google │ │ └── cloud │ │ └── broker │ │ └── encryption │ │ ├── GenerateDEK.java │ │ └── backends │ │ ├── CloudKMSBackend.java │ │ └── keyset │ │ ├── CloudStorageKeysetManager.java │ │ ├── FilesystemKeysetManager.java │ │ ├── KeysetManager.java │ │ └── KeysetUtils.java │ └── test │ └── java │ └── com │ └── google │ └── cloud │ └── broker │ └── encryption │ └── backends │ └── CloudKMSBackendTest.java ├── docs ├── concepts │ ├── authentication.md │ ├── authorizer.md │ ├── broker-server.md │ ├── caching.md │ ├── connector.md │ ├── database.md │ ├── encryption.md │ ├── index.md │ ├── logging.md │ ├── providers.md │ ├── secret-management.md │ ├── sessions.md │ ├── settings.md │ ├── tls.md │ └── user-mapping.md ├── contribute │ ├── development.md │ ├── index.md │ ├── load-tests.md │ └── regression-tests.md ├── deploy │ └── index.md ├── img │ ├── access-example-service-accounts.svg │ ├── access-example-users.svg │ ├── delegated-auth-architecture.svg │ ├── delegated-auth-sequence.svg │ ├── delegated-auth-sequence.txt │ ├── demo-architecture.svg │ ├── direct-auth-architecture.svg │ ├── direct-auth-sequence.svg │ ├── direct-auth-sequence.txt │ ├── dwd-admin-screen.png │ └── dwd-service-accounts-screen.png ├── index.md └── tutorials │ └── index.md ├── init-action └── broker-hadoop-connector.sh ├── kubernetes └── broker-server │ └── templates │ └── session-cleanup.yaml ├── load-testing ├── brokerservice │ └── protobuf │ │ └── broker.proto ├── client.py ├── install.sh ├── locustfile.py └── settings.py.template ├── pom.xml ├── run.sh └── terraform ├── broker.tf ├── client.tf ├── misc.tf ├── origin_kdc.tf ├── peering.tf ├── shadow.tf ├── startup-script-kdc.tpl ├── variables.tf └── versions.tf /.dockerignore: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Google LLC 2 | # Licensed under the Apache License, Version 2.0 (the "License"); 3 | # you may not use this file except in compliance with the License. 4 | # You may obtain a copy of the License at 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # Unless required by applicable law or agreed to in writing, software 7 | # distributed under the License is distributed on an "AS IS" BASIS, 8 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | # See the License for the specific language governing permissions and 10 | # limitations under the License. 11 | 12 | # Ignore all by default: 13 | * 14 | 15 | # Allowlist only the required assets: 16 | !/code/authorizer/install.sh 17 | !code/broker-server/install.sh 18 | !code/built-jars 19 | !code/authorizer/target/authorizer-*-jar-with-dependencies.jar 20 | !code/broker-server/target/broker-server-*-jar-with-dependencies.jar 21 | !code/extensions/caching/cloud-datastore/target/cache-backend-cloud-datastore-*-jar-with-dependencies.jar 22 | !code/extensions/caching/redis/target/cache-backend-redis-*-jar-with-dependencies.jar 23 | !code/extensions/database/jdbc/target/database-backend-jdbc-*-jar-with-dependencies.jar 24 | !code/extensions/database/cloud-datastore/target/database-backend-cloud-datastore-*-jar-with-dependencies.jar 25 | !code/extensions/encryption/cloud-kms/target/encryption-backend-cloud-kms-*-jar-with-dependencies.jar -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Google LLC 2 | # Licensed under the Apache License, Version 2.0 (the "License"); 3 | # you may not use this file except in compliance with the License. 4 | # You may obtain a copy of the License at 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # Unless required by applicable law or agreed to in writing, software 7 | # distributed under the License is distributed on an "AS IS" BASIS, 8 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | # See the License for the specific language governing permissions and 10 | # limitations under the License. 11 | 12 | # Terraform artifacts: 13 | terraform/terraform.tfstate* 14 | terraform/.terraform* 15 | terraform/*.tfvars 16 | 17 | # Load testing artifacts 18 | load-testing/settings.py 19 | load-testing/brokerservice/protobuf/broker_pb2_grpc.py 20 | load-testing/brokerservice/protobuf/broker_pb2.py 21 | 22 | # Unit testing artifacts 23 | service-account-key.json 24 | 25 | # Custom deployment specific files 26 | deploy/** 27 | 28 | # Java artifacts 29 | *.jar 30 | **/target/** 31 | dependency-reduced-pom.xml 32 | code/built-jars 33 | 34 | # Redis artifacts 35 | dump.rdb 36 | 37 | # Secrets 38 | client_secret*.json 39 | *.keytab 40 | *.crt 41 | *.key 42 | *.csr 43 | *.pem 44 | dek.json 45 | 46 | # Ignore .DS_Store (folder metadata file in OS X) 47 | *.DS_Store 48 | 49 | # Ignore IDE specific files 50 | .idea 51 | *.iml 52 | 53 | # NodeJS 54 | npm-debug.log -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # How to Contribute 2 | 3 | We'd love to accept your patches and contributions to this project. There are 4 | just a few small guidelines you need to follow. 5 | 6 | Check out all the details in the [documentation](docs/contribute/index.md). 7 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # GCP Token Broker 2 | 3 | ## About this project 4 | 5 | The GCP Token Broker enables end-to-end Kerberos security and Cloud IAM integration for Hadoop 6 | workloads on [Google Cloud Platform](https://cloud.google.com/) (GCP). 7 | 8 | This project aims to achieve the following goals: 9 | 10 | * Bridge the gap between Kerberos and Cloud IAM to allow users to log in with Kerberos and access GCP resources. 11 | * Enable multi-tenancy for Hadoop clusters on Compute Engine and Cloud Dataproc. 12 | * Enable user impersonation by Hadoop services such as Hive, Presto, or Oozie. 13 | 14 | This project also strives to address the following requirements, which many enterprise customers have when 15 | they're looking to migrate on-premise workloads to the cloud: 16 | 17 | * All access to GCP resources (Cloud Storage, Google BigQuery, Cloud Bigtable, etc) should be attributable 18 | to the individual users who initiated the requests. 19 | * No long-lived credentials should be stored on client machines or worker nodes. 20 | * Cause as few changes as possible to existing on-premise security systems and user workflows. 21 | 22 | ## Documentation 23 | 24 | See the full documentation [here](docs/index.md). 25 | 26 | ## Repository's contents 27 | 28 | This repository contains: 29 | 30 | - `apps`: Server applications, including: 31 | - `authorizer`: Web UI for the OAuth flow that users must go through to authorize the broker service. 32 | - `broker`: The broker service itself. 33 | - `deploy`: Helm charts for deploying the broker service and the authorizer app to a Kubernetes cluster. 34 | - `docs`: Technical documentation for this project. 35 | - `connector`: Extension for the GCS Connector to allow Hadoop to communicate with the broker. 36 | - `init-action`: Initialization action to install the broker dependencies in 37 | a Cloud Dataproc cluster. 38 | - `load-testing`: Scripts for running loads tests for the broker service. 39 | - `terraform`: Terraform scripts to deploy a sample demo environment. This is 40 | provided only as a reference and **_should not_** be used as-is in production. 41 | 42 | ## Roadmap 43 | 44 | Included in the current **early** release: 45 | 46 | * Full lifecycle of Hadoop-style delegation tokens: creation, renewal, cancellation. 47 | * Support for Hadoop-style proxy users. 48 | * Authentication backend: Kerberos. 49 | * Target GCP service: Cloud Storage. 50 | * Database backends: Cloud Datastore, JDBC. 51 | * Cache backend: Redis on Cloud Memorystore. 52 | 53 | Plans for the **stable** releases: 54 | 55 | * Performance optimizations. 56 | * API stabilization. 57 | 58 | Plans for **future** releases: 59 | 60 | * Target GCP services: BigQuery, Cloud Bigtable, Cloud PubSub. 61 | * Database backends: Cloud Firestore, Cloud Bigtable. 62 | * Cache backends: Memcached, Cloud Bigtable. 63 | * Support for more authentication backends: TBD. 64 | 65 | ## How to Contribute 66 | 67 | We'd love to accept your patches and contributions to this project. There are 68 | just a few small guidelines you need to follow. See the [contributing guide](docs/contribute/index.md) 69 | for more details. 70 | -------------------------------------------------------------------------------- /VERSION: -------------------------------------------------------------------------------- 1 | 0.10.5 -------------------------------------------------------------------------------- /code/authorizer/Dockerfile: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Google LLC 2 | # Licensed under the Apache License, Version 2.0 (the "License"); 3 | # you may not use this file except in compliance with the License. 4 | # You may obtain a copy of the License at 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # Unless required by applicable law or agreed to in writing, software 7 | # distributed under the License is distributed on an "AS IS" BASIS, 8 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | # See the License for the specific language governing permissions and 10 | # limitations under the License. 11 | 12 | FROM ubuntu:18.04 13 | 14 | COPY ./code/authorizer/install.sh /base/code/authorizer/install.sh 15 | 16 | RUN /base/code/authorizer/install.sh 17 | 18 | COPY ./code/authorizer/target/authorizer-*-jar-with-dependencies.jar /classpath/authorizer.jar 19 | COPY ./code/extensions/database/jdbc/target/database-backend-jdbc-*-jar-with-dependencies.jar /classpath/database-backend-jdbc.jar 20 | COPY ./code/extensions/database/cloud-datastore/target/database-backend-cloud-datastore-*-jar-with-dependencies.jar /classpath/database-backend-cloud-datastore.jar 21 | COPY ./code/extensions/encryption/cloud-kms/target/encryption-backend-cloud-kms-*-jar-with-dependencies.jar /classpath/encryption-backend-cloud-kms.jar 22 | 23 | WORKDIR /base/code/authorizer 24 | 25 | ENTRYPOINT ["java", "-cp", "/classpath/*", "com.google.cloud.broker.apps.authorizer.Authorizer"] -------------------------------------------------------------------------------- /code/authorizer/install.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Copyright 2020 Google LLC 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # Unless required by applicable law or agreed to in writing, software 9 | # distributed under the License is distributed on an "AS IS" BASIS, 10 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | # See the License for the specific language governing permissions and 12 | # limitations under the License. 13 | 14 | apt-get update 15 | 16 | DEBIAN_FRONTEND=noninteractive apt-get install -y \ 17 | krb5-user \ 18 | libkrb5-dev \ 19 | openjdk-11-jre-headless -------------------------------------------------------------------------------- /code/authorizer/src/main/resources/index.soy: -------------------------------------------------------------------------------- 1 | /** 2 | Copyright 2020 Google LLC 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | {namespace Authorizer.Templates} 18 | 19 | {template .index} 20 | {@param GOOGLE_LOGIN_URI: string} 21 | 22 | 23 | GCP Token Broker 24 | 25 | 26 |

Welcome to the GCP Token Broker authorization page!

27 |

To authorize the broker, click this button then follow the log-in steps:

28 | 29 | 30 | 31 | {/template} 32 | -------------------------------------------------------------------------------- /code/authorizer/src/main/resources/reference.conf: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Google LLC 2 | # Licensed under the Apache License, Version 2.0 (the "License"); 3 | # you may not use this file except in compliance with the License. 4 | # You may obtain a copy of the License at 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # Unless required by applicable law or agreed to in writing, software 7 | # distributed under the License is distributed on an "AS IS" BASIS, 8 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | # See the License for the specific language governing permissions and 10 | # limitations under the License. 11 | 12 | # Default values for some of the Authorizer settings 13 | 14 | authorizer { 15 | host = "0.0.0.0" 16 | port = 8080 17 | } 18 | logging { 19 | level = "INFO" 20 | } 21 | database { 22 | backend = "com.google.cloud.broker.database.backends.CloudDatastoreBackend" 23 | } 24 | encryption { 25 | backend = "com.google.cloud.broker.encryption.backends.CloudKMSBackend" 26 | } 27 | secret-manager { 28 | downloads = [] 29 | } 30 | remote-cache.backend = "com.google.cloud.broker.caching.remote.DummyCache" 31 | system-check-enabled = true -------------------------------------------------------------------------------- /code/authorizer/src/main/resources/server_error.soy: -------------------------------------------------------------------------------- 1 | /** 2 | Copyright 2020 Google LLC 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | {namespace Authorizer.Templates} 18 | 19 | {template .server_error} 20 | 21 | 22 | GCP Token Broker 23 | 24 | 25 |

Server error

26 | 27 | 28 | {/template} 29 | -------------------------------------------------------------------------------- /code/authorizer/src/main/resources/success.soy: -------------------------------------------------------------------------------- 1 | /** 2 | Copyright 2020 Google LLC 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | {namespace Authorizer.Templates} 18 | 19 | {template .success} 20 | 21 | 22 | Authorization complete 23 | 24 | 25 |

Authorization complete

26 |

Congratulations! You are now authorized to use the GCP Token Broker.

27 | 28 | 29 | {/template} -------------------------------------------------------------------------------- /code/authorizer/src/test/java/com/google/cloud/broker/apps/authorizer/TemplateTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.google.cloud.broker.apps.authorizer; 18 | 19 | import com.google.common.collect.ImmutableMap; 20 | import com.google.common.io.Resources; 21 | import com.google.template.soy.SoyFileSet; 22 | import com.google.template.soy.jbcsrc.api.SoySauce; 23 | import java.util.Map; 24 | import org.junit.BeforeClass; 25 | import org.junit.Test; 26 | 27 | public class TemplateTest { 28 | private static SoySauce soySauce; 29 | 30 | @BeforeClass 31 | public static void setup() { 32 | SoyFileSet sfs = 33 | SoyFileSet.builder() 34 | .add(Resources.getResource("index.soy")) 35 | .add(Resources.getResource("success.soy")) 36 | .build(); 37 | soySauce = sfs.compileTemplates(); 38 | } 39 | 40 | @Test 41 | public void testIndex() { 42 | Map data = 43 | ImmutableMap.builder() 44 | .put("principal", "user@EXAMPLE.COM") 45 | .put("email", "user@example.com") 46 | .put("picture", "https://cdn.example.com/user.jpg") 47 | .build(); 48 | String content = 49 | soySauce 50 | .renderTemplate("Authorizer.Templates.success") 51 | .setData(data) 52 | .renderHtml() 53 | .get() 54 | .getContent(); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /code/broker-server/Dockerfile: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Google LLC 2 | # Licensed under the Apache License, Version 2.0 (the "License"); 3 | # you may not use this file except in compliance with the License. 4 | # You may obtain a copy of the License at 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # Unless required by applicable law or agreed to in writing, software 7 | # distributed under the License is distributed on an "AS IS" BASIS, 8 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | # See the License for the specific language governing permissions and 10 | # limitations under the License. 11 | 12 | FROM ubuntu:18.04 13 | 14 | COPY ./code/broker-server/install.sh /base/code/broker-server/install.sh 15 | 16 | RUN /base/code/broker-server/install.sh 17 | 18 | COPY ./code/broker-server/target/broker-server-*-jar-with-dependencies.jar /classpath/broker-server.jar 19 | COPY ./code/extensions/caching/cloud-datastore/target/cache-backend-cloud-datastore-*-jar-with-dependencies.jar /classpath/cache-backend-cloud-datastore.jar 20 | COPY ./code/extensions/caching/redis/target/cache-backend-redis-*-jar-with-dependencies.jar /classpath/cache-backend-redis.jar 21 | COPY ./code/extensions/database/jdbc/target/database-backend-jdbc-*-jar-with-dependencies.jar /classpath/database-backend-jdbc.jar 22 | COPY ./code/extensions/database/cloud-datastore/target/database-backend-cloud-datastore-*-jar-with-dependencies.jar /classpath/database-backend-cloud-datastore.jar 23 | COPY ./code/extensions/encryption/cloud-kms/target/encryption-backend-cloud-kms-*-jar-with-dependencies.jar /classpath/encryption-backend-cloud-kms.jar 24 | 25 | WORKDIR /base/code/broker 26 | 27 | ENTRYPOINT ["java", "-cp", "/classpath/*", "com.google.cloud.broker.apps.brokerserver.BrokerServer"] -------------------------------------------------------------------------------- /code/broker-server/descriptor.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 17 | 18 | 27 | jar-with-dependencies 28 | 29 | jar 30 | 31 | false 32 | 33 | 34 | / 35 | true 36 | true 37 | runtime 38 | 39 | 40 | 41 | 42 | metaInf-services 43 | 44 | 45 | -------------------------------------------------------------------------------- /code/broker-server/install-dev.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Copyright 2020 Google LLC 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # Unless required by applicable law or agreed to in writing, software 9 | # distributed under the License is distributed on an "AS IS" BASIS, 10 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | # See the License for the specific language governing permissions and 12 | # limitations under the License. 13 | 14 | set -xeuo pipefail 15 | 16 | source "/base/code/broker-server/install.sh" 17 | 18 | # Maven and its dependencies 19 | apt-get install -y libatomic1 maven 20 | 21 | # Create a script to restart services 22 | touch /restart-services.sh 23 | chmod u+x /restart-services.sh 24 | 25 | # PostgreSQL 26 | echo exit 0 > /usr/sbin/policy-rc.d 27 | DEBIAN_FRONTEND=noninteractive apt-get install -y postgresql 28 | echo "CREATE ROLE testuser LOGIN ENCRYPTED PASSWORD 'UNSECURE-PASSWORD';" | su postgres -c "psql" 29 | su postgres -c "createdb broker --owner testuser" 30 | echo "service postgresql restart" >> /restart-services.sh 31 | # Make the Postgres server available outside the container 32 | sed -Ei "s/#listen_addresses\s+=\s+'localhost'/listen_addresses = '*'/g" /etc/postgresql/*/main/postgresql.conf 33 | echo "host all all 0.0.0.0/0 md5" >> /etc/postgresql/14/main/pg_hba.conf 34 | 35 | # MariaDB 36 | apt install -y mariadb-server 37 | echo "CREATE DATABASE broker DEFAULT CHARACTER SET utf8 DEFAULT COLLATE utf8_general_ci;" | mariadb 38 | echo "CREATE USER 'testuser' IDENTIFIED BY 'UNSECURE-PASSWORD';" | mariadb 39 | echo "GRANT ALL privileges ON *.* TO 'testuser'@'%';" | mariadb 40 | echo "service mariadb restart" >> /restart-services.sh 41 | # Make the MariaDB server available outside the container 42 | sed -Ei 's/bind-address\s+=\s+127.0.0.1/bind-address=0.0.0.0/g' /etc/mysql/mariadb.conf.d/50-server.cnf 43 | 44 | # Redis 45 | apt-get install -y redis-server 46 | # Apparently need to run 'shutdown' as 'service stop' and 'service restart' don't seem to kill the process 47 | echo "redis-cli shutdown; service redis-server start" >> /restart-services.sh 48 | # Make the Redis server available outside the container 49 | sed 's/^bind 127.0.0.1 ::1/bind 0.0.0.0/' -i /etc/redis/redis.conf 50 | sed 's/^protected-mode yes/protected-mode no/' -i /etc/redis/redis.conf 51 | 52 | # Node.JS tools 53 | apt install -y npm 54 | npm install --global remark-cli remark-validate-links # Used for code linting (`./run.sh lint`) 55 | export NODE_PATH="/usr/local/lib/node_modules" 56 | 57 | # (Re)start all services 58 | /restart-services.sh -------------------------------------------------------------------------------- /code/broker-server/install.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Copyright 2020 Google LLC 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # Unless required by applicable law or agreed to in writing, software 9 | # distributed under the License is distributed on an "AS IS" BASIS, 10 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | # See the License for the specific language governing permissions and 12 | # limitations under the License. 13 | 14 | apt-get update 15 | 16 | DEBIAN_FRONTEND=noninteractive apt-get install -y \ 17 | krb5-user \ 18 | libkrb5-dev \ 19 | openjdk-11-jre-headless -------------------------------------------------------------------------------- /code/broker-server/src/main/java/com/google/cloud/broker/apps/brokerserver/ClientAddressServerInterceptor.java: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Google LLC 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // You may obtain a copy of the License at 5 | // http://www.apache.org/licenses/LICENSE-2.0 6 | // Unless required by applicable law or agreed to in writing, software 7 | // distributed under the License is distributed on an "AS IS" BASIS, 8 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | // See the License for the specific language governing permissions and 10 | // limitations under the License. 11 | 12 | package com.google.cloud.broker.apps.brokerserver; 13 | 14 | import io.grpc.*; 15 | 16 | public class ClientAddressServerInterceptor implements ServerInterceptor { 17 | 18 | public static final Context.Key CLIENT_ADDRESS_CONTEXT_KEY = Context.key("ClientAddress"); 19 | 20 | @Override 21 | public ServerCall.Listener interceptCall( 22 | ServerCall serverCall, 23 | Metadata metadata, 24 | ServerCallHandler serverCallHandler) { 25 | String clientAddress = 26 | serverCall.getAttributes().get(Grpc.TRANSPORT_ATTR_REMOTE_ADDR).toString(); 27 | Context ctx = Context.current().withValue(CLIENT_ADDRESS_CONTEXT_KEY, clientAddress); 28 | return Contexts.interceptCall(ctx, serverCall, metadata, serverCallHandler); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /code/broker-server/src/main/java/com/google/cloud/broker/apps/brokerserver/accesstokens/AccessToken.java: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Google LLC 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // You may obtain a copy of the License at 5 | // http://www.apache.org/licenses/LICENSE-2.0 6 | // Unless required by applicable law or agreed to in writing, software 7 | // distributed under the License is distributed on an "AS IS" BASIS, 8 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | // See the License for the specific language governing permissions and 10 | // limitations under the License. 11 | 12 | package com.google.cloud.broker.apps.brokerserver.accesstokens; 13 | 14 | import com.fasterxml.jackson.annotation.JsonCreator; 15 | import com.fasterxml.jackson.annotation.JsonProperty; 16 | 17 | public class AccessToken { 18 | 19 | private String value; 20 | private long expiresAt; 21 | 22 | @JsonCreator 23 | public AccessToken( 24 | @JsonProperty("value") String value, @JsonProperty("expiresAt") long expiresAt) { 25 | this.value = value; 26 | this.expiresAt = expiresAt; 27 | } 28 | 29 | @JsonProperty("value") 30 | public String getValue() { 31 | return value; 32 | } 33 | 34 | @JsonProperty("expiresAt") 35 | public long getExpiresAt() { 36 | return expiresAt; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /code/broker-server/src/main/java/com/google/cloud/broker/apps/brokerserver/accesstokens/providers/AbstractProvider.java: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Google LLC 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // You may obtain a copy of the License at 5 | // http://www.apache.org/licenses/LICENSE-2.0 6 | // Unless required by applicable law or agreed to in writing, software 7 | // distributed under the License is distributed on an "AS IS" BASIS, 8 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | // See the License for the specific language governing permissions and 10 | // limitations under the License. 11 | 12 | package com.google.cloud.broker.apps.brokerserver.accesstokens.providers; 13 | 14 | import com.google.cloud.broker.apps.brokerserver.accesstokens.AccessToken; 15 | import com.google.cloud.broker.settings.AppSettings; 16 | import com.google.cloud.broker.utils.InstanceUtils; 17 | import java.util.List; 18 | 19 | public abstract class AbstractProvider { 20 | 21 | private static AbstractProvider instance; 22 | 23 | public static AbstractProvider getInstance() { 24 | String className = AppSettings.getInstance().getString(AppSettings.PROVIDER_BACKEND); 25 | if (instance == null || !className.equals(instance.getClass().getCanonicalName())) { 26 | instance = (AbstractProvider) InstanceUtils.invokeConstructor(className); 27 | } 28 | return instance; 29 | } 30 | 31 | public abstract AccessToken getAccessToken(String googleIdentity, List scopes); 32 | } 33 | -------------------------------------------------------------------------------- /code/broker-server/src/main/java/com/google/cloud/broker/apps/brokerserver/accesstokens/providers/AbstractUserProvider.java: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Google LLC 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // You may obtain a copy of the License at 5 | // http://www.apache.org/licenses/LICENSE-2.0 6 | // Unless required by applicable law or agreed to in writing, software 7 | // distributed under the License is distributed on an "AS IS" BASIS, 8 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | // See the License for the specific language governing permissions and 10 | // limitations under the License. 11 | 12 | package com.google.cloud.broker.apps.brokerserver.accesstokens.providers; 13 | 14 | public abstract class AbstractUserProvider extends AbstractProvider {} 15 | -------------------------------------------------------------------------------- /code/broker-server/src/main/java/com/google/cloud/broker/apps/brokerserver/accesstokens/providers/HybridProvider.java: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Google LLC 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // You may obtain a copy of the License at 5 | // http://www.apache.org/licenses/LICENSE-2.0 6 | // Unless required by applicable law or agreed to in writing, software 7 | // distributed under the License is distributed on an "AS IS" BASIS, 8 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | // See the License for the specific language governing permissions and 10 | // limitations under the License. 11 | 12 | package com.google.cloud.broker.apps.brokerserver.accesstokens.providers; 13 | 14 | import com.google.cloud.broker.apps.brokerserver.accesstokens.AccessToken; 15 | import com.google.cloud.broker.settings.AppSettings; 16 | import com.google.cloud.broker.utils.InstanceUtils; 17 | import java.util.List; 18 | 19 | public class HybridProvider extends AbstractProvider { 20 | 21 | AbstractUserProvider userProvider; 22 | ServiceAccountProvider serviceAccountProvider; 23 | 24 | public HybridProvider() { 25 | String className = AppSettings.getInstance().getString(AppSettings.HYBRID_USER_PROVIDER); 26 | userProvider = (AbstractUserProvider) InstanceUtils.invokeConstructor(className); 27 | serviceAccountProvider = new ServiceAccountProvider(); 28 | } 29 | 30 | @Override 31 | public AccessToken getAccessToken(String googleIdentity, List scopes) { 32 | if (googleIdentity.endsWith(".iam.gserviceaccount.com")) { 33 | return serviceAccountProvider.getAccessToken(googleIdentity, scopes); 34 | } else { 35 | return userProvider.getAccessToken(googleIdentity, scopes); 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /code/broker-server/src/main/java/com/google/cloud/broker/apps/brokerserver/accesstokens/providers/RevokeRefreshTokens.java: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Google LLC 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // You may obtain a copy of the License at 5 | // http://www.apache.org/licenses/LICENSE-2.0 6 | // Unless required by applicable law or agreed to in writing, software 7 | // distributed under the License is distributed on an "AS IS" BASIS, 8 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | // See the License for the specific language governing permissions and 10 | // limitations under the License. 11 | 12 | package com.google.cloud.broker.apps.brokerserver.accesstokens.providers; 13 | 14 | import com.google.cloud.broker.database.backends.AbstractDatabaseBackend; 15 | import com.google.cloud.broker.database.models.Model; 16 | import com.google.cloud.broker.oauth.RefreshToken; 17 | import com.google.cloud.broker.oauth.RefreshTokenUtils; 18 | import com.google.cloud.broker.utils.TimeUtils; 19 | import java.lang.invoke.MethodHandles; 20 | import java.util.List; 21 | import org.slf4j.Logger; 22 | import org.slf4j.LoggerFactory; 23 | 24 | public class RevokeRefreshTokens { 25 | 26 | private static final Class klass = MethodHandles.lookup().lookupClass(); 27 | private static final Logger logger = LoggerFactory.getLogger(klass); 28 | 29 | public static void main(String[] args) { 30 | long numHours; 31 | if (args.length == 1) { 32 | numHours = Long.parseLong(args[0]); 33 | } else { 34 | throw new IllegalArgumentException("Wrong arguments"); 35 | } 36 | long numMilliseconds = numHours * 3600 * 1000; 37 | long now = TimeUtils.currentTimeMillis(); 38 | List models = AbstractDatabaseBackend.getInstance().getAll(RefreshToken.class); 39 | int numRevokedToken = 0; 40 | for (Model model : models) { 41 | RefreshToken token = (RefreshToken) model; 42 | if (now >= token.getCreationTime() + numMilliseconds) { 43 | // Revoke the token 44 | RefreshTokenUtils.revoke(token); 45 | // Delete the token from the database 46 | AbstractDatabaseBackend.getInstance().delete(token); 47 | numRevokedToken++; 48 | } 49 | } 50 | logger.info( 51 | klass.getSimpleName() + " - Revoked and deleted refresh token(s): " + numRevokedToken); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /code/broker-server/src/main/java/com/google/cloud/broker/apps/brokerserver/accesstokens/providers/ServiceAccountProvider.java: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Google LLC 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // You may obtain a copy of the License at 5 | // http://www.apache.org/licenses/LICENSE-2.0 6 | // Unless required by applicable law or agreed to in writing, software 7 | // distributed under the License is distributed on an "AS IS" BASIS, 8 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | // See the License for the specific language governing permissions and 10 | // limitations under the License. 11 | 12 | package com.google.cloud.broker.apps.brokerserver.accesstokens.providers; 13 | 14 | import com.google.auth.oauth2.GoogleCredentials; 15 | import com.google.auth.oauth2.ImpersonatedCredentials; 16 | import com.google.cloud.broker.apps.brokerserver.accesstokens.AccessToken; 17 | import io.grpc.Status; 18 | import java.io.IOException; 19 | import java.util.List; 20 | 21 | public class ServiceAccountProvider extends AbstractProvider { 22 | 23 | @Override 24 | public AccessToken getAccessToken(String googleIdentity, List scopes) { 25 | if (!googleIdentity.endsWith(".iam.gserviceaccount.com")) { 26 | throw new IllegalArgumentException( 27 | "Google identity `" + googleIdentity + "` is not a service account"); 28 | } 29 | try { 30 | GoogleCredentials credentials = GoogleCredentials.getApplicationDefault(); 31 | ImpersonatedCredentials impersonatedCredentials = 32 | ImpersonatedCredentials.create(credentials, googleIdentity, null, scopes, 3600); 33 | com.google.auth.oauth2.AccessToken token = impersonatedCredentials.refreshAccessToken(); 34 | return new AccessToken(token.getTokenValue(), token.getExpirationTime().getTime()); 35 | } catch (IOException e) { 36 | throw Status.PERMISSION_DENIED.asRuntimeException(); 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /code/broker-server/src/main/java/com/google/cloud/broker/apps/brokerserver/accesstokens/providers/experimental/JSONFileCredentialsProvider.java: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Google LLC 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // You may obtain a copy of the License at 5 | // http://www.apache.org/licenses/LICENSE-2.0 6 | // Unless required by applicable law or agreed to in writing, software 7 | // distributed under the License is distributed on an "AS IS" BASIS, 8 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | // See the License for the specific language governing permissions and 10 | // limitations under the License. 11 | 12 | package com.google.cloud.broker.apps.brokerserver.accesstokens.providers.experimental; 13 | 14 | import com.google.auth.oauth2.GoogleCredentials; 15 | import com.google.cloud.broker.apps.brokerserver.accesstokens.AccessToken; 16 | import com.google.cloud.broker.apps.brokerserver.accesstokens.providers.AbstractProvider; 17 | import com.google.cloud.broker.settings.AppSettings; 18 | import io.grpc.Status; 19 | import java.io.ByteArrayInputStream; 20 | import java.io.IOException; 21 | import java.nio.file.Files; 22 | import java.nio.file.NoSuchFileException; 23 | import java.nio.file.Path; 24 | import java.nio.file.Paths; 25 | import java.util.List; 26 | 27 | /** 28 | * Uses the credentials in a JSON file to generate access tokens. The JSON file can contain a 29 | * Service Account key file in JSON format from the Google Developers Console or a stored user 30 | * credential using the format supported by the Cloud SDK. This is an experimental backend that 31 | * might be removed or modified in a future release. This is NOT recommended for production. 32 | */ 33 | public class JSONFileCredentialsProvider extends AbstractProvider { 34 | 35 | private static String AUTHZ_ERROR_MESSAGE = 36 | "GCP Token Broker authorization is invalid or has expired for identity: %s"; 37 | 38 | @Override 39 | public AccessToken getAccessToken(String googleIdentity, List scopes) { 40 | try { 41 | String basedir = 42 | AppSettings.getInstance().getString(AppSettings.JSON_FILE_CREDENTIALS_PROVIDER_BASE_DIR); 43 | Path path = Paths.get(basedir, googleIdentity.split("@")[0] + ".json"); 44 | GoogleCredentials credentials = 45 | GoogleCredentials.fromStream(new ByteArrayInputStream(Files.readAllBytes(path))); 46 | com.google.auth.oauth2.AccessToken token = 47 | credentials.createScoped(scopes).refreshAccessToken(); 48 | return new AccessToken(token.getTokenValue(), token.getExpirationTime().getTime()); 49 | } catch (NoSuchFileException e) { 50 | throw Status.PERMISSION_DENIED 51 | .withDescription(String.format(AUTHZ_ERROR_MESSAGE, googleIdentity)) 52 | .asRuntimeException(); 53 | } catch (IOException e) { 54 | throw new RuntimeException(e); 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /code/broker-server/src/main/java/com/google/cloud/broker/apps/brokerserver/sessions/SessionAuthenticator.java: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Google LLC 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // You may obtain a copy of the License at 5 | // http://www.apache.org/licenses/LICENSE-2.0 6 | // Unless required by applicable law or agreed to in writing, software 7 | // distributed under the License is distributed on an "AS IS" BASIS, 8 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | // See the License for the specific language governing permissions and 10 | // limitations under the License. 11 | 12 | package com.google.cloud.broker.apps.brokerserver.sessions; 13 | 14 | import com.google.cloud.broker.authentication.AuthorizationHeaderServerInterceptor; 15 | import io.grpc.Status; 16 | 17 | public class SessionAuthenticator { 18 | 19 | public Session authenticateSession() { 20 | String authorizationHeader = 21 | AuthorizationHeaderServerInterceptor.BROKER_AUTHORIZATION_CONTEXT_KEY.get(); 22 | 23 | // Make sure this is indeed 24 | if (!authorizationHeader.startsWith("BrokerSession ")) { 25 | return null; 26 | } 27 | 28 | // Extract the session token from the authorization header 29 | String token = authorizationHeader.split("\\s")[1]; 30 | 31 | Session session = (Session) new SessionCacheFetcher(token).fetch(); 32 | 33 | if (session.isExpired()) { 34 | throw Status.UNAUTHENTICATED 35 | .withDescription("Expired session ID: " + session.getId()) 36 | .asRuntimeException(); 37 | } 38 | 39 | return session; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /code/broker-server/src/main/java/com/google/cloud/broker/apps/brokerserver/sessions/SessionCacheFetcher.java: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Google LLC 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // You may obtain a copy of the License at 5 | // http://www.apache.org/licenses/LICENSE-2.0 6 | // Unless required by applicable law or agreed to in writing, software 7 | // distributed under the License is distributed on an "AS IS" BASIS, 8 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | // See the License for the specific language governing permissions and 10 | // limitations under the License. 11 | 12 | package com.google.cloud.broker.apps.brokerserver.sessions; 13 | 14 | import com.fasterxml.jackson.databind.ObjectMapper; 15 | import com.google.cloud.broker.caching.CacheFetcher; 16 | import com.google.cloud.broker.settings.AppSettings; 17 | import java.io.IOException; 18 | 19 | public class SessionCacheFetcher extends CacheFetcher { 20 | 21 | private String rawToken; 22 | 23 | public SessionCacheFetcher(String rawToken) { 24 | this.rawToken = rawToken; 25 | // Disallow remote cache because the cache key contains sensitive information 26 | // (i.e. the session tokens) 27 | this.allowRemoteCache = false; 28 | } 29 | 30 | @Override 31 | protected String getCacheKey() { 32 | return String.format("session-%s", rawToken); 33 | } 34 | 35 | @Override 36 | protected int getLocalCacheTime() { 37 | return AppSettings.getInstance().getInt(AppSettings.SESSION_LOCAL_CACHE_TIME); 38 | } 39 | 40 | @Override 41 | protected int getRemoteCacheTime() { 42 | // Remote cache not enabled 43 | throw new UnsupportedOperationException(); 44 | } 45 | 46 | @Override 47 | protected Object computeResult() { 48 | return SessionTokenUtils.getSessionFromRawToken(rawToken); 49 | } 50 | 51 | @Override 52 | protected Object fromJson(String json) throws IOException { 53 | ObjectMapper objectMapper = new ObjectMapper(); 54 | return objectMapper.readValue(json, Session.class); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /code/broker-server/src/main/java/com/google/cloud/broker/apps/brokerserver/sessions/SessionCleanup.java: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Google LLC 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // You may obtain a copy of the License at 5 | // http://www.apache.org/licenses/LICENSE-2.0 6 | // Unless required by applicable law or agreed to in writing, software 7 | // distributed under the License is distributed on an "AS IS" BASIS, 8 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | // See the License for the specific language governing permissions and 10 | // limitations under the License. 11 | 12 | package com.google.cloud.broker.apps.brokerserver.sessions; 13 | 14 | import com.google.cloud.broker.database.backends.AbstractDatabaseBackend; 15 | import com.google.cloud.broker.utils.TimeUtils; 16 | import java.lang.invoke.MethodHandles; 17 | import org.slf4j.Logger; 18 | import org.slf4j.LoggerFactory; 19 | 20 | public class SessionCleanup { 21 | 22 | private static final Class klass = MethodHandles.lookup().lookupClass(); 23 | private static final Logger logger = LoggerFactory.getLogger(klass); 24 | 25 | public static void main(String[] args) { 26 | Integer numItems = null; 27 | if (args.length > 0) { 28 | numItems = Integer.parseInt(args[0]); 29 | } 30 | long now = TimeUtils.currentTimeMillis(); 31 | int numDeletedSessions = 32 | AbstractDatabaseBackend.getInstance() 33 | .deleteExpiredItems(Session.class, "expiresAt", now, numItems); 34 | logger.info(klass.getSimpleName() + " - Deleted expired session(s): " + numDeletedSessions); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /code/broker-server/src/main/java/com/google/cloud/broker/apps/brokerserver/sessions/SessionToken.java: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Google LLC 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // You may obtain a copy of the License at 5 | // http://www.apache.org/licenses/LICENSE-2.0 6 | // Unless required by applicable law or agreed to in writing, software 7 | // distributed under the License is distributed on an "AS IS" BASIS, 8 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | // See the License for the specific language governing permissions and 10 | // limitations under the License. 11 | 12 | package com.google.cloud.broker.apps.brokerserver.sessions; 13 | 14 | class SessionToken { 15 | 16 | private String sessionId; 17 | private byte[] signature; 18 | 19 | SessionToken(String sessionId, byte[] signature) { 20 | this.sessionId = sessionId; 21 | this.signature = signature; 22 | } 23 | 24 | String getSessionId() { 25 | return sessionId; 26 | } 27 | 28 | byte[] getSignature() { 29 | return signature; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /code/broker-server/src/main/java/com/google/cloud/broker/apps/brokerserver/validation/GrpcRequestValidation.java: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Google LLC 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // You may obtain a copy of the License at 5 | // http://www.apache.org/licenses/LICENSE-2.0 6 | // Unless required by applicable law or agreed to in writing, software 7 | // distributed under the License is distributed on an "AS IS" BASIS, 8 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | // See the License for the specific language governing permissions and 10 | // limitations under the License. 11 | 12 | package com.google.cloud.broker.apps.brokerserver.validation; 13 | 14 | import io.grpc.Status; 15 | import java.util.*; 16 | 17 | public class GrpcRequestValidation { 18 | 19 | public static void validateParameterIsEmpty(String parameter, String value) { 20 | if (value.length() > 0) { 21 | throw Status.INVALID_ARGUMENT 22 | .withDescription(String.format("Request's parameter `%s` must be empty", parameter)) 23 | .asRuntimeException(); 24 | } 25 | } 26 | 27 | public static void validateParameterIsEmpty(String parameter, List values) { 28 | if (values.size() > 0) { 29 | throw Status.INVALID_ARGUMENT 30 | .withDescription(String.format("Request's parameter `%s` must be empty", parameter)) 31 | .asRuntimeException(); 32 | } 33 | } 34 | 35 | public static void validateParameterNotEmpty(String parameter, String value) { 36 | if (value.length() == 0) { 37 | throw Status.INVALID_ARGUMENT 38 | .withDescription(String.format("Request must provide `%s`", parameter)) 39 | .asRuntimeException(); 40 | } 41 | } 42 | 43 | public static void validateParameterNotEmpty(String parameter, List values) { 44 | if (values.size() == 0) { 45 | throw Status.INVALID_ARGUMENT 46 | .withDescription(String.format("Request must provide `%s`", parameter)) 47 | .asRuntimeException(); 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /code/broker-server/src/main/java/com/google/cloud/broker/apps/brokerserver/validation/ScopeValidation.java: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Google LLC 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // You may obtain a copy of the License at 5 | // http://www.apache.org/licenses/LICENSE-2.0 6 | // Unless required by applicable law or agreed to in writing, software 7 | // distributed under the License is distributed on an "AS IS" BASIS, 8 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | // See the License for the specific language governing permissions and 10 | // limitations under the License. 11 | 12 | package com.google.cloud.broker.apps.brokerserver.validation; 13 | 14 | import com.google.cloud.broker.settings.AppSettings; 15 | import io.grpc.Status; 16 | import java.util.HashSet; 17 | import java.util.List; 18 | import java.util.Set; 19 | 20 | public class ScopeValidation { 21 | 22 | public static void validateScopes(List scopes) { 23 | List allowlist = AppSettings.getInstance().getStringList(AppSettings.SCOPES_ALLOWLIST); 24 | Set scopeSet = new HashSet(scopes); 25 | Set allowlistSet = new HashSet(allowlist); 26 | if (!allowlistSet.containsAll(scopeSet)) { 27 | throw Status.PERMISSION_DENIED 28 | .withDescription( 29 | String.format("`[%s]` are not allowlisted scopes", String.join(",", scopes))) 30 | .asRuntimeException(); 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /code/broker-server/src/main/proto/broker.proto: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Google LLC 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // You may obtain a copy of the License at 5 | // http://www.apache.org/licenses/LICENSE-2.0 6 | // Unless required by applicable law or agreed to in writing, software 7 | // distributed under the License is distributed on an "AS IS" BASIS, 8 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | // See the License for the specific language governing permissions and 10 | // limitations under the License. 11 | 12 | syntax = "proto3"; 13 | 14 | option java_multiple_files = true; 15 | option java_package = "com.google.cloud.broker.apps.brokerserver.protobuf"; 16 | option java_outer_classname = "BrokerProto"; 17 | 18 | package com.google.cloud.broker.apps.brokerserver.protobuf; 19 | 20 | 21 | // Get session token request/response -------------------------- 22 | 23 | message GetSessionTokenRequest { 24 | repeated string scopes = 1; 25 | string owner = 2; 26 | string target = 3; 27 | string renewer = 4; 28 | } 29 | 30 | message GetSessionTokenResponse { 31 | string session_token = 1; 32 | } 33 | 34 | // Renew session token request/response ------------------------ 35 | 36 | message RenewSessionTokenRequest { 37 | string session_token = 1; 38 | } 39 | 40 | message RenewSessionTokenResponse { 41 | int64 expires_at = 2; 42 | } 43 | 44 | // Cancel session token request/response ----------------------- 45 | 46 | message CancelSessionTokenRequest { 47 | string session_token = 1; 48 | } 49 | 50 | message CancelSessionTokenResponse { 51 | } 52 | 53 | // Get access token request/response --------------------------- 54 | 55 | message GetAccessTokenRequest { 56 | repeated string scopes = 1; 57 | string owner = 2; 58 | string target = 3; 59 | } 60 | 61 | message GetAccessTokenResponse { 62 | string access_token = 1; 63 | int64 expires_at = 2; 64 | } 65 | 66 | 67 | // Broker service ----------------------------------------- 68 | 69 | service Broker { 70 | rpc GetSessionToken(GetSessionTokenRequest) returns (GetSessionTokenResponse) {} 71 | rpc RenewSessionToken(RenewSessionTokenRequest) returns (RenewSessionTokenResponse) {} 72 | rpc CancelSessionToken(CancelSessionTokenRequest) returns (CancelSessionTokenResponse) {} 73 | rpc GetAccessToken(GetAccessTokenRequest) returns (GetAccessTokenResponse) {} 74 | } -------------------------------------------------------------------------------- /code/broker-server/src/main/resources/logback.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /code/broker-server/src/main/resources/reference.conf: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Google LLC 2 | # Licensed under the Apache License, Version 2.0 (the "License"); 3 | # you may not use this file except in compliance with the License. 4 | # You may obtain a copy of the License at 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # Unless required by applicable law or agreed to in writing, software 7 | # distributed under the License is distributed on an "AS IS" BASIS, 8 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | # See the License for the specific language governing permissions and 10 | # limitations under the License. 11 | 12 | # Default values for some of the broker server settings 13 | 14 | server { 15 | host = "0.0.0.0" 16 | port = 8080 17 | tls { 18 | enabled = true 19 | } 20 | } 21 | 22 | sessions { 23 | local-cache-time = 30 24 | maximum-lifetime = 604800000 25 | renew-period = 86400000 26 | } 27 | 28 | proxy-users = [] 29 | 30 | scopes { 31 | allowlist = ["https://www.googleapis.com/auth/devstorage.read_write"] 32 | } 33 | 34 | provider { 35 | backend = "com.google.cloud.broker.apps.brokerserver.accesstokens.providers.HybridProvider" 36 | access-tokens { 37 | local-cache-time = 30 38 | remote-cache-time = 60 39 | boundary-permissions = [ 40 | "inRole:roles/storage.objectAdmin", 41 | "inRole:roles/storage.legacyBucketReader" 42 | ] 43 | } 44 | 45 | # Specific providers' settings 46 | hybrid { 47 | user-provider = "com.google.cloud.broker.apps.brokerserver.accesstokens.providers.RefreshTokenProvider" 48 | } 49 | json-file-credentials { 50 | base-dir = "" 51 | } 52 | } 53 | 54 | user-mapping { 55 | mapper = "com.google.cloud.broker.usermapping.KerberosUserMapper" 56 | } 57 | 58 | remote-cache { 59 | backend = "com.google.cloud.broker.caching.remote.RedisCache" 60 | 61 | # Specific backends' settings 62 | redis { 63 | host = "localhost" 64 | port = 6379 65 | db = 0 66 | } 67 | } 68 | 69 | authentication { 70 | backend = "com.google.cloud.broker.authentication.backends.SpnegoAuthenticator" 71 | } 72 | 73 | logging { 74 | level = "INFO" 75 | } 76 | 77 | database { 78 | backend = "com.google.cloud.broker.database.backends.CloudDatastoreBackend" 79 | } 80 | 81 | encryption { 82 | backend = "com.google.cloud.broker.encryption.backends.CloudKMSBackend" 83 | } 84 | 85 | secret-manager { 86 | downloads = [] 87 | } 88 | 89 | system-check-enabled = true -------------------------------------------------------------------------------- /code/broker-server/src/test/java/com/google/cloud/broker/apps/brokerserver/accesstokens/MockAccessBoundary.java: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Google LLC 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // You may obtain a copy of the License at 5 | // http://www.apache.org/licenses/LICENSE-2.0 6 | // Unless required by applicable law or agreed to in writing, software 7 | // distributed under the License is distributed on an "AS IS" BASIS, 8 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | // See the License for the specific language governing permissions and 10 | // limitations under the License. 11 | 12 | package com.google.cloud.broker.apps.brokerserver.accesstokens; 13 | 14 | import static org.mockito.ArgumentMatchers.any; 15 | import static org.mockito.ArgumentMatchers.anyString; 16 | import static org.powermock.api.mockito.PowerMockito.mockStatic; 17 | 18 | import org.powermock.api.mockito.PowerMockito; 19 | 20 | public class MockAccessBoundary { 21 | 22 | public static void mock() { 23 | mockStatic(AccessBoundaryUtils.class); 24 | PowerMockito.when(AccessBoundaryUtils.addAccessBoundary(any(), anyString())) 25 | .thenAnswer( 26 | invocation -> { 27 | AccessToken accessToken = (AccessToken) invocation.getArgument(0); 28 | String target = (String) invocation.getArgument(1); 29 | return new AccessToken( 30 | accessToken.getValue() + ";Target=" + target, accessToken.getExpiresAt()); 31 | }); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /code/broker-server/src/test/java/com/google/cloud/broker/apps/brokerserver/accesstokens/providers/AbstractProviderTest.java: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Google LLC 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // You may obtain a copy of the License at 5 | // http://www.apache.org/licenses/LICENSE-2.0 6 | // Unless required by applicable law or agreed to in writing, software 7 | // distributed under the License is distributed on an "AS IS" BASIS, 8 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | // See the License for the specific language governing permissions and 10 | // limitations under the License. 11 | 12 | package com.google.cloud.broker.apps.brokerserver.accesstokens.providers; 13 | 14 | import static org.junit.Assert.*; 15 | 16 | import com.google.cloud.broker.settings.AppSettings; 17 | import com.google.cloud.broker.settings.SettingsOverride; 18 | import java.util.Map; 19 | import org.junit.Test; 20 | 21 | public class AbstractProviderTest { 22 | 23 | @Test 24 | public void testGetInstance() { 25 | try (SettingsOverride override = 26 | SettingsOverride.apply(Map.of(AppSettings.PROVIDER_BACKEND, "com.example.DoesNotExist"))) { 27 | try { 28 | AbstractProvider.getInstance(); 29 | fail(); 30 | } catch (RuntimeException e) { 31 | assertEquals("java.lang.ClassNotFoundException: com.example.DoesNotExist", e.getMessage()); 32 | } 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /code/broker-server/src/test/java/com/google/cloud/broker/apps/brokerserver/accesstokens/providers/DomainWideDelegationAuthorityProviderTest.java: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Google LLC 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // You may obtain a copy of the License at 5 | // http://www.apache.org/licenses/LICENSE-2.0 6 | // Unless required by applicable law or agreed to in writing, software 7 | // distributed under the License is distributed on an "AS IS" BASIS, 8 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | // See the License for the specific language governing permissions and 10 | // limitations under the License. 11 | 12 | package com.google.cloud.broker.apps.brokerserver.accesstokens.providers; 13 | 14 | import static org.junit.Assert.*; 15 | 16 | import io.grpc.Status; 17 | import io.grpc.StatusRuntimeException; 18 | import java.util.List; 19 | import org.junit.Test; 20 | 21 | public class DomainWideDelegationAuthorityProviderTest { 22 | 23 | // TODO: Still needs tests: 24 | // - Happy path 25 | 26 | private static final List SCOPES = 27 | List.of("https://www.googleapis.com/auth/devstorage.read_write"); 28 | 29 | @Test 30 | public void testUnauthorized() { 31 | DomainWideDelegationAuthorityProvider provider = new DomainWideDelegationAuthorityProvider(); 32 | try { 33 | provider.getAccessToken("bob@example.com", SCOPES); 34 | fail(); 35 | } catch (StatusRuntimeException e) { 36 | assertEquals(Status.PERMISSION_DENIED.getCode(), e.getStatus().getCode()); 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /code/broker-server/src/test/java/com/google/cloud/broker/apps/brokerserver/accesstokens/providers/HybridProviderTest.java: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Google LLC 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // You may obtain a copy of the License at 5 | // http://www.apache.org/licenses/LICENSE-2.0 6 | // Unless required by applicable law or agreed to in writing, software 7 | // distributed under the License is distributed on an "AS IS" BASIS, 8 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | // See the License for the specific language governing permissions and 10 | // limitations under the License. 11 | 12 | package com.google.cloud.broker.apps.brokerserver.accesstokens.providers; 13 | 14 | import static org.junit.Assert.*; 15 | import static org.junit.Assert.assertTrue; 16 | 17 | import com.google.cloud.broker.apps.brokerserver.accesstokens.AccessToken; 18 | import com.google.cloud.broker.database.backends.DummyDatabaseBackend; 19 | import com.google.cloud.broker.settings.AppSettings; 20 | import com.google.cloud.broker.settings.SettingsOverride; 21 | import java.nio.charset.StandardCharsets; 22 | import java.util.List; 23 | import java.util.Map; 24 | import org.junit.*; 25 | 26 | public class HybridProviderTest { 27 | 28 | // TODO: Still needs tests: 29 | // - Happy path. 30 | 31 | private static final List SCOPES = 32 | List.of("https://www.googleapis.com/auth/devstorage.read_write"); 33 | private static final String projectId = 34 | AppSettings.getInstance().getString(AppSettings.GCP_PROJECT); 35 | 36 | @ClassRule 37 | public static SettingsOverride settingsOverride = 38 | new SettingsOverride( 39 | Map.of( 40 | AppSettings.USER_MAPPER, "com.google.cloud.broker.usermapping.MockUserMapper", 41 | AppSettings.HYBRID_USER_PROVIDER, 42 | "com.google.cloud.broker.apps.brokerserver.accesstokens.providers.MockProvider")); 43 | 44 | @After 45 | public void teardown() { 46 | // Clear the database 47 | DummyDatabaseBackend.getCache().clear(); 48 | } 49 | 50 | @Test 51 | public void testUser() { 52 | HybridProvider provider = new HybridProvider(); 53 | AccessToken accessToken = provider.getAccessToken("alice@example.com", SCOPES); 54 | assertEquals( 55 | "FakeAccessToken/GoogleIdentity=alice@example.com;Scopes=" + String.join(",", SCOPES), 56 | accessToken.getValue()); 57 | } 58 | 59 | @Test 60 | public void testServiceAccount() { 61 | HybridProvider provider = new HybridProvider(); 62 | AccessToken accessToken = 63 | provider.getAccessToken("alice-shadow@" + projectId + ".iam.gserviceaccount.com", SCOPES); 64 | assertTrue(accessToken.getValue().startsWith("ya29.")); 65 | assertEquals(1024, accessToken.getValue().getBytes(StandardCharsets.UTF_8).length); 66 | assertTrue(accessToken.getExpiresAt() > 0); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /code/broker-server/src/test/java/com/google/cloud/broker/apps/brokerserver/accesstokens/providers/MockProvider.java: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Google LLC 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // You may obtain a copy of the License at 5 | // http://www.apache.org/licenses/LICENSE-2.0 6 | // Unless required by applicable law or agreed to in writing, software 7 | // distributed under the License is distributed on an "AS IS" BASIS, 8 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | // See the License for the specific language governing permissions and 10 | // limitations under the License. 11 | 12 | package com.google.cloud.broker.apps.brokerserver.accesstokens.providers; 13 | 14 | import com.google.cloud.broker.apps.brokerserver.accesstokens.AccessToken; 15 | import java.util.List; 16 | 17 | /** Mock provider only used for testing. Do NOT use in production! */ 18 | public class MockProvider extends AbstractUserProvider { 19 | 20 | @Override 21 | public AccessToken getAccessToken(String googleIdentity, List scopes) { 22 | return new AccessToken( 23 | "FakeAccessToken/GoogleIdentity=" + googleIdentity + ";Scopes=" + String.join(",", scopes), 24 | 999999999L); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /code/broker-server/src/test/java/com/google/cloud/broker/apps/brokerserver/accesstokens/providers/RefreshTokenProviderTest.java: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Google LLC 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // You may obtain a copy of the License at 5 | // http://www.apache.org/licenses/LICENSE-2.0 6 | // Unless required by applicable law or agreed to in writing, software 7 | // distributed under the License is distributed on an "AS IS" BASIS, 8 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | // See the License for the specific language governing permissions and 10 | // limitations under the License. 11 | 12 | package com.google.cloud.broker.apps.brokerserver.accesstokens.providers; 13 | 14 | import static org.junit.Assert.*; 15 | 16 | import com.google.cloud.broker.database.backends.DummyDatabaseBackend; 17 | import com.google.cloud.broker.settings.AppSettings; 18 | import com.google.cloud.broker.settings.SettingsOverride; 19 | import io.grpc.Status; 20 | import io.grpc.StatusRuntimeException; 21 | import java.util.List; 22 | import java.util.Map; 23 | import org.junit.*; 24 | 25 | public class RefreshTokenProviderTest { 26 | 27 | // TODO: Still needs tests: 28 | // - Happy path. 29 | 30 | private static final List SCOPES = 31 | List.of("https://www.googleapis.com/auth/devstorage.read_write"); 32 | 33 | @ClassRule 34 | public static SettingsOverride settingsOverride = 35 | new SettingsOverride( 36 | Map.of( 37 | AppSettings.DATABASE_BACKEND, 38 | "com.google.cloud.broker.database.backends.DummyDatabaseBackend", 39 | AppSettings.USER_MAPPER, "com.google.cloud.broker.usermapping.MockUserMapper")); 40 | 41 | @After 42 | public void teardown() { 43 | // Clear the database 44 | DummyDatabaseBackend.getCache().clear(); 45 | } 46 | 47 | @Test 48 | public void testUnauthorized() { 49 | RefreshTokenProvider provider = new RefreshTokenProvider(); 50 | try { 51 | provider.getAccessToken("bob@example.com", SCOPES); 52 | fail("StatusRuntimeException not thrown"); 53 | } catch (StatusRuntimeException e) { 54 | assertEquals(Status.PERMISSION_DENIED.getCode(), e.getStatus().getCode()); 55 | assertEquals( 56 | "GCP Token Broker authorization is invalid or has expired for identity: bob@example.com", 57 | e.getStatus().getDescription()); 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /code/broker-server/src/test/java/com/google/cloud/broker/apps/brokerserver/sessions/SessionTest.java: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Google LLC 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // You may obtain a copy of the License at 5 | // http://www.apache.org/licenses/LICENSE-2.0 6 | // Unless required by applicable law or agreed to in writing, software 7 | // distributed under the License is distributed on an "AS IS" BASIS, 8 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | // See the License for the specific language governing permissions and 10 | // limitations under the License. 11 | 12 | package com.google.cloud.broker.apps.brokerserver.sessions; 13 | 14 | import static org.junit.Assert.*; 15 | 16 | import com.google.cloud.broker.database.models.Model; 17 | import java.util.HashMap; 18 | import org.junit.Test; 19 | 20 | public class SessionTest { 21 | 22 | private static final String ALICE = "alice@EXAMPLE.COM"; 23 | private static final String YARN = "yarn@FOO.BAR"; 24 | private static final String GCS = "https://www.googleapis.com/auth/devstorage.read_write"; 25 | private static final String MOCK_BUCKET = "//storage.googleapis.com/projects/_/buckets/example"; 26 | 27 | // TODO: testToMap 28 | 29 | @Test 30 | public void testFromMap() { 31 | HashMap values = new HashMap(); 32 | values.put("id", "123456789"); 33 | values.put("owner", ALICE); 34 | values.put("renewer", YARN); 35 | values.put("target", MOCK_BUCKET); 36 | values.put("scopes", GCS); 37 | values.put("creationTime", 11111111111111L); 38 | values.put("expiresAt", 2222222222222L); 39 | 40 | Session session = (Session) Model.fromMap(Session.class, values); 41 | assertEquals("123456789", session.getId()); 42 | assertEquals(ALICE, session.getOwner()); 43 | assertEquals(YARN, session.getRenewer()); 44 | assertEquals(MOCK_BUCKET, session.getTarget()); 45 | assertEquals(GCS, session.getScopes()); 46 | assertEquals(11111111111111L, session.getCreationTime().longValue()); 47 | assertEquals(2222222222222L, session.getExpiresAt().longValue()); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /code/broker-server/src/test/java/com/google/cloud/broker/authentication/backends/MockAuthenticator.java: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Google LLC 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // You may obtain a copy of the License at 5 | // http://www.apache.org/licenses/LICENSE-2.0 6 | // Unless required by applicable law or agreed to in writing, software 7 | // distributed under the License is distributed on an "AS IS" BASIS, 8 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | // See the License for the specific language governing permissions and 10 | // limitations under the License. 11 | 12 | package com.google.cloud.broker.authentication.backends; 13 | 14 | import io.grpc.Status; 15 | 16 | /** 17 | * Used only for testing. Do NOT use in production. This is a dummy authenticator that returns the 18 | * provided token as the authenticated user. In other terms, to allow this authenticator to 19 | * authenticate a user, simply pass the user name in the token, e.g.: "Negotiate: alice@EXAMPLE.COM" 20 | */ 21 | public class MockAuthenticator extends AbstractAuthenticationBackend { 22 | 23 | public MockAuthenticator() {} 24 | 25 | @Override 26 | public String authenticateUser(String authorizationHeader) { 27 | if (!authorizationHeader.startsWith("Negotiate ")) { 28 | throw Status.UNAUTHENTICATED.asRuntimeException(); 29 | } 30 | return authorizationHeader.split("\\s")[1]; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /code/broker-server/src/test/java/com/google/cloud/broker/usermapping/MockUserMapper.java: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Google LLC 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // You may obtain a copy of the License at 5 | // http://www.apache.org/licenses/LICENSE-2.0 6 | // Unless required by applicable law or agreed to in writing, software 7 | // distributed under the License is distributed on an "AS IS" BASIS, 8 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | // See the License for the specific language governing permissions and 10 | // limitations under the License. 11 | 12 | package com.google.cloud.broker.usermapping; 13 | 14 | public class MockUserMapper extends AbstractUserMapper { 15 | 16 | @Override 17 | public String map(String name) throws IllegalArgumentException { 18 | return name.split("@")[0] + "@altostrat.com"; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /code/client/client-lib/src/main/java/com/google/cloud/broker/client/connect/BrokerServerInfo.java: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Google LLC 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // You may obtain a copy of the License at 5 | // http://www.apache.org/licenses/LICENSE-2.0 6 | // Unless required by applicable law or agreed to in writing, software 7 | // distributed under the License is distributed on an "AS IS" BASIS, 8 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | // See the License for the specific language governing permissions and 10 | // limitations under the License. 11 | 12 | package com.google.cloud.broker.client.connect; 13 | 14 | public class BrokerServerInfo { 15 | 16 | private String serverUri; 17 | private String kerberosPrincipal; 18 | private String certificate; 19 | private String certificatePath; 20 | 21 | public BrokerServerInfo( 22 | String serverUri, String kerberosPrincipal, String certificate, String certificatePath) { 23 | this.serverUri = serverUri; 24 | this.kerberosPrincipal = kerberosPrincipal; 25 | this.certificate = certificate; 26 | this.certificatePath = certificatePath; 27 | } 28 | 29 | public String getServerUri() { 30 | return serverUri; 31 | } 32 | 33 | public void setServerUri(String serverUri) { 34 | this.serverUri = serverUri; 35 | } 36 | 37 | public String getKerberosPrincipal() { 38 | return kerberosPrincipal; 39 | } 40 | 41 | public void setKerberosPrincipal(String kerberosPrincipal) { 42 | this.kerberosPrincipal = kerberosPrincipal; 43 | } 44 | 45 | public String getCertificate() { 46 | return certificate; 47 | } 48 | 49 | public void setCertificate(String certificate) { 50 | this.certificate = certificate; 51 | } 52 | 53 | public String getCertificatePath() { 54 | return certificatePath; 55 | } 56 | 57 | public void setCertificatePath(String certificatePath) { 58 | this.certificatePath = certificatePath; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /code/client/client-lib/src/main/java/com/google/cloud/broker/client/credentials/BrokerKerberosCredentials.java: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Google LLC 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // You may obtain a copy of the License at 5 | // http://www.apache.org/licenses/LICENSE-2.0 6 | // Unless required by applicable law or agreed to in writing, software 7 | // distributed under the License is distributed on an "AS IS" BASIS, 8 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | // See the License for the specific language governing permissions and 10 | // limitations under the License. 11 | 12 | package com.google.cloud.broker.client.credentials; 13 | 14 | import com.google.auth.oauth2.AccessToken; 15 | import com.google.cloud.broker.client.connect.BrokerServerInfo; 16 | import com.google.cloud.broker.client.endpoints.GetAccessToken; 17 | 18 | public class BrokerKerberosCredentials extends BrokerBaseCredentials { 19 | 20 | private String owner; 21 | private Iterable scopes; 22 | private String target; 23 | 24 | public BrokerKerberosCredentials( 25 | BrokerServerInfo serverInfo, String owner, Iterable scopes, String target) { 26 | super(serverInfo); 27 | this.owner = owner; 28 | this.scopes = scopes; 29 | this.target = target; 30 | } 31 | 32 | @Override 33 | public AccessToken refreshAccessToken() { 34 | return GetAccessToken.submitDirectAuth(serverInfo, owner, scopes, target); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /code/client/client-lib/src/main/java/com/google/cloud/broker/client/credentials/BrokerSessionCredentials.java: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Google LLC 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // You may obtain a copy of the License at 5 | // http://www.apache.org/licenses/LICENSE-2.0 6 | // Unless required by applicable law or agreed to in writing, software 7 | // distributed under the License is distributed on an "AS IS" BASIS, 8 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | // See the License for the specific language governing permissions and 10 | // limitations under the License. 11 | 12 | package com.google.cloud.broker.client.credentials; 13 | 14 | import com.google.auth.oauth2.AccessToken; 15 | import com.google.cloud.broker.client.connect.BrokerServerInfo; 16 | import com.google.cloud.broker.client.endpoints.GetAccessToken; 17 | 18 | public class BrokerSessionCredentials extends BrokerBaseCredentials { 19 | 20 | private String sessionToken; 21 | 22 | public BrokerSessionCredentials(BrokerServerInfo serverInfo, String sessionToken) { 23 | super(serverInfo); 24 | this.sessionToken = sessionToken; 25 | } 26 | 27 | public AccessToken refreshAccessToken() { 28 | return GetAccessToken.submitDelegatedAuth(serverInfo, sessionToken); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /code/client/client-lib/src/main/java/com/google/cloud/broker/client/endpoints/CancelSessionToken.java: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Google LLC 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // You may obtain a copy of the License at 5 | // http://www.apache.org/licenses/LICENSE-2.0 6 | // Unless required by applicable law or agreed to in writing, software 7 | // distributed under the License is distributed on an "AS IS" BASIS, 8 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | // See the License for the specific language governing permissions and 10 | // limitations under the License. 11 | 12 | package com.google.cloud.broker.client.endpoints; 13 | 14 | import com.google.cloud.broker.apps.brokerserver.protobuf.CancelSessionTokenRequest; 15 | import com.google.cloud.broker.client.connect.BrokerGateway; 16 | import com.google.cloud.broker.client.connect.BrokerServerInfo; 17 | 18 | public class CancelSessionToken { 19 | 20 | public static void submit(BrokerServerInfo serverInfo, String sessionToken) { 21 | BrokerGateway gateway = new BrokerGateway(serverInfo); 22 | gateway.setSPNEGOToken(); 23 | CancelSessionTokenRequest request = 24 | CancelSessionTokenRequest.newBuilder().setSessionToken(sessionToken).build(); 25 | gateway.getStub().cancelSessionToken(request); 26 | gateway.getManagedChannel().shutdown(); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /code/client/client-lib/src/main/java/com/google/cloud/broker/client/endpoints/GetAccessToken.java: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Google LLC 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // You may obtain a copy of the License at 5 | // http://www.apache.org/licenses/LICENSE-2.0 6 | // Unless required by applicable law or agreed to in writing, software 7 | // distributed under the License is distributed on an "AS IS" BASIS, 8 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | // See the License for the specific language governing permissions and 10 | // limitations under the License. 11 | 12 | package com.google.cloud.broker.client.endpoints; 13 | 14 | import com.google.auth.oauth2.AccessToken; 15 | import com.google.cloud.broker.apps.brokerserver.protobuf.GetAccessTokenRequest; 16 | import com.google.cloud.broker.apps.brokerserver.protobuf.GetAccessTokenResponse; 17 | import com.google.cloud.broker.client.connect.BrokerGateway; 18 | import com.google.cloud.broker.client.connect.BrokerServerInfo; 19 | import java.util.Date; 20 | 21 | public class GetAccessToken { 22 | 23 | public static AccessToken submitDirectAuth( 24 | BrokerServerInfo serverInfo, String owner, Iterable scopes, String target) { 25 | BrokerGateway gateway = new BrokerGateway(serverInfo); 26 | try { 27 | gateway.setSPNEGOToken(); 28 | } catch (Exception e) { 29 | throw new RuntimeException( 30 | String.format( 31 | "Error while getting SPNEGO token for owner=`%s`, scopes=`%s`, target=`%s`", 32 | owner, scopes, target), 33 | e); 34 | } 35 | GetAccessTokenRequest request = 36 | GetAccessTokenRequest.newBuilder() 37 | .addAllScopes(scopes) 38 | .setOwner(owner) 39 | .setTarget(target) 40 | .build(); 41 | GetAccessTokenResponse response = gateway.getStub().getAccessToken(request); 42 | gateway.getManagedChannel().shutdown(); 43 | String tokenString = response.getAccessToken(); 44 | long expiresAt = response.getExpiresAt(); 45 | return new AccessToken(tokenString, new Date(expiresAt)); 46 | } 47 | 48 | public static AccessToken submitDelegatedAuth(BrokerServerInfo serverInfo, String sessionToken) { 49 | BrokerGateway gateway = new BrokerGateway(serverInfo); 50 | gateway.setSessionToken(sessionToken); 51 | GetAccessTokenRequest request = GetAccessTokenRequest.newBuilder().build(); 52 | GetAccessTokenResponse response = gateway.getStub().getAccessToken(request); 53 | gateway.getManagedChannel().shutdown(); 54 | String tokenString = response.getAccessToken(); 55 | long expiresAt = response.getExpiresAt(); 56 | return new AccessToken(tokenString, new Date(expiresAt)); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /code/client/client-lib/src/main/java/com/google/cloud/broker/client/endpoints/GetSessionToken.java: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Google LLC 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // You may obtain a copy of the License at 5 | // http://www.apache.org/licenses/LICENSE-2.0 6 | // Unless required by applicable law or agreed to in writing, software 7 | // distributed under the License is distributed on an "AS IS" BASIS, 8 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | // See the License for the specific language governing permissions and 10 | // limitations under the License. 11 | 12 | package com.google.cloud.broker.client.endpoints; 13 | 14 | import com.google.cloud.broker.apps.brokerserver.protobuf.GetSessionTokenRequest; 15 | import com.google.cloud.broker.apps.brokerserver.protobuf.GetSessionTokenResponse; 16 | import com.google.cloud.broker.client.connect.BrokerGateway; 17 | import com.google.cloud.broker.client.connect.BrokerServerInfo; 18 | 19 | public class GetSessionToken { 20 | 21 | public static String submit( 22 | BrokerServerInfo serverInfo, 23 | String owner, 24 | String renewer, 25 | Iterable scopes, 26 | String target) { 27 | BrokerGateway gateway = new BrokerGateway(serverInfo); 28 | try { 29 | gateway.setSPNEGOToken(); 30 | } catch (Exception e) { 31 | throw new RuntimeException( 32 | String.format( 33 | "Error while getting SPNEGO token for owner=`%s`, renewer=`%s`, scopes=`%s`, target=`%s`", 34 | owner, renewer, scopes, target), 35 | e); 36 | } 37 | GetSessionTokenRequest request = 38 | GetSessionTokenRequest.newBuilder() 39 | .addAllScopes(scopes) 40 | .setOwner(owner) 41 | .setRenewer(renewer) 42 | .setTarget(target) 43 | .build(); 44 | GetSessionTokenResponse response = gateway.getStub().getSessionToken(request); 45 | gateway.getManagedChannel().shutdown(); 46 | return response.getSessionToken(); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /code/client/client-lib/src/main/java/com/google/cloud/broker/client/endpoints/RenewSessionToken.java: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Google LLC 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // You may obtain a copy of the License at 5 | // http://www.apache.org/licenses/LICENSE-2.0 6 | // Unless required by applicable law or agreed to in writing, software 7 | // distributed under the License is distributed on an "AS IS" BASIS, 8 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | // See the License for the specific language governing permissions and 10 | // limitations under the License. 11 | 12 | package com.google.cloud.broker.client.endpoints; 13 | 14 | import com.google.cloud.broker.apps.brokerserver.protobuf.RenewSessionTokenRequest; 15 | import com.google.cloud.broker.apps.brokerserver.protobuf.RenewSessionTokenResponse; 16 | import com.google.cloud.broker.client.connect.BrokerGateway; 17 | import com.google.cloud.broker.client.connect.BrokerServerInfo; 18 | 19 | public class RenewSessionToken { 20 | 21 | public static long submit(BrokerServerInfo serverInfo, String sessionToken) { 22 | BrokerGateway gateway = new BrokerGateway(serverInfo); 23 | gateway.setSPNEGOToken(); 24 | RenewSessionTokenRequest request = 25 | RenewSessionTokenRequest.newBuilder().setSessionToken(sessionToken).build(); 26 | RenewSessionTokenResponse response = gateway.getStub().renewSessionToken(request); 27 | gateway.getManagedChannel().shutdown(); 28 | return response.getExpiresAt(); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /code/client/client-lib/src/main/java/com/google/cloud/broker/client/utils/GrpcUtils.java: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Google LLC 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // You may obtain a copy of the License at 5 | // http://www.apache.org/licenses/LICENSE-2.0 6 | // Unless required by applicable law or agreed to in writing, software 7 | // distributed under the License is distributed on an "AS IS" BASIS, 8 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | // See the License for the specific language governing permissions and 10 | // limitations under the License. 11 | 12 | package com.google.cloud.broker.client.utils; 13 | 14 | import com.google.cloud.broker.apps.brokerserver.protobuf.BrokerGrpc; 15 | import io.grpc.ManagedChannel; 16 | import io.grpc.netty.shaded.io.grpc.netty.GrpcSslContexts; 17 | import io.grpc.netty.shaded.io.grpc.netty.NettyChannelBuilder; 18 | import io.grpc.netty.shaded.io.netty.handler.ssl.SslContext; 19 | import io.grpc.netty.shaded.io.netty.handler.ssl.SslContextBuilder; 20 | import java.io.ByteArrayInputStream; 21 | import java.io.InputStream; 22 | import java.util.concurrent.Executors; 23 | import java.util.concurrent.TimeUnit; 24 | import javax.net.ssl.SSLException; 25 | 26 | public class GrpcUtils { 27 | 28 | public static ManagedChannel newManagedChannel( 29 | String brokerHostname, int brokerPort, boolean useTLS, String tlsCertificate) { 30 | // Create the gRPC stub 31 | NettyChannelBuilder channelBuilder = NettyChannelBuilder.forAddress(brokerHostname, brokerPort); 32 | if (!useTLS) { 33 | channelBuilder.usePlaintext(); 34 | } else { 35 | SslContextBuilder sslContextBuilder; 36 | if (tlsCertificate == null || tlsCertificate.equals("")) { 37 | sslContextBuilder = GrpcSslContexts.forClient(); 38 | } else { 39 | // A certificate is provided, so add it to the stub's build 40 | InputStream inputStream = new ByteArrayInputStream(tlsCertificate.getBytes()); 41 | try { 42 | sslContextBuilder = GrpcSslContexts.forClient().trustManager(inputStream); 43 | } catch (IllegalArgumentException e) { 44 | throw new IllegalArgumentException( 45 | "The provided certificate for the broker service is invalid"); 46 | } 47 | } 48 | try { 49 | SslContext sslContext = sslContextBuilder.build(); 50 | channelBuilder.sslContext(sslContext); 51 | } catch (SSLException e) { 52 | throw new RuntimeException(e); 53 | } 54 | } 55 | return channelBuilder.executor(Executors.newSingleThreadExecutor()).build(); 56 | } 57 | 58 | public static BrokerGrpc.BrokerBlockingStub newStub(ManagedChannel managedChannel) { 59 | int DEADLINE_MILLISECONDS = 20 * 1000; // Timeout for RPC calls 60 | return BrokerGrpc.newBlockingStub(managedChannel) 61 | .withDeadlineAfter(DEADLINE_MILLISECONDS, TimeUnit.MILLISECONDS); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /code/client/client-lib/src/main/java/com/google/cloud/broker/client/utils/OAuthUtils.java: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Google LLC 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // You may obtain a copy of the License at 5 | // http://www.apache.org/licenses/LICENSE-2.0 6 | // Unless required by applicable law or agreed to in writing, software 7 | // distributed under the License is distributed on an "AS IS" BASIS, 8 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | // See the License for the specific language governing permissions and 10 | // limitations under the License. 11 | 12 | package com.google.cloud.broker.client.utils; 13 | 14 | import com.google.auth.oauth2.GoogleCredentials; 15 | import com.google.auth.oauth2.IdTokenCredentials; 16 | import com.google.auth.oauth2.IdTokenProvider; 17 | import java.io.IOException; 18 | 19 | public class OAuthUtils { 20 | 21 | public static GoogleCredentials getApplicationDefaultCredentials() { 22 | GoogleCredentials credentials; 23 | try { 24 | credentials = GoogleCredentials.getApplicationDefault(); 25 | if (!(credentials instanceof IdTokenProvider)) { 26 | throw new IllegalArgumentException("Credentials are not an instance of IdTokenProvider."); 27 | } 28 | return credentials; 29 | } catch (IOException e) { 30 | throw new RuntimeException(e); 31 | } 32 | } 33 | 34 | public static com.google.auth.oauth2.AccessToken getApplicationDefaultIdToken(String audience) { 35 | try { 36 | GoogleCredentials credentials = getApplicationDefaultCredentials(); 37 | if (!(credentials instanceof IdTokenProvider)) { 38 | throw new IllegalArgumentException("Credentials are not an instance of IdTokenProvider."); 39 | } 40 | IdTokenCredentials tokenCredential = 41 | IdTokenCredentials.newBuilder() 42 | .setIdTokenProvider((IdTokenProvider) credentials) 43 | .setTargetAudience(audience) 44 | .build(); 45 | return tokenCredential.refreshAccessToken(); 46 | } catch (IOException e) { 47 | throw new RuntimeException(e); 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /code/client/client-lib/src/main/java/com/google/cloud/broker/client/utils/SpnegoUtils.java: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Google LLC 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // You may obtain a copy of the License at 5 | // http://www.apache.org/licenses/LICENSE-2.0 6 | // Unless required by applicable law or agreed to in writing, software 7 | // distributed under the License is distributed on an "AS IS" BASIS, 8 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | // See the License for the specific language governing permissions and 10 | // limitations under the License. 11 | 12 | package com.google.cloud.broker.client.utils; 13 | 14 | import org.ietf.jgss.*; 15 | 16 | public final class SpnegoUtils { 17 | 18 | private static final String SPNEGO_OID = "1.3.6.1.5.5.2"; 19 | private static final String KRB5_MECHANISM_OID = "1.2.840.113554.1.2.2"; 20 | private static final String KRB5_PRINCIPAL_NAME_OID = "1.2.840.113554.1.2.2.1"; 21 | 22 | public static byte[] newSPNEGOToken(String servicePrincipal) throws GSSException { 23 | // Create GSS context for the broker service and the logged-in user 24 | Oid krb5Mechanism = new Oid(KRB5_MECHANISM_OID); 25 | Oid krb5PrincipalNameType = new Oid(KRB5_PRINCIPAL_NAME_OID); 26 | Oid spnegoOid = new Oid(SPNEGO_OID); 27 | GSSManager manager = GSSManager.getInstance(); 28 | GSSName gssServerName = 29 | manager.createName(servicePrincipal, krb5PrincipalNameType, krb5Mechanism); 30 | GSSContext gssContext = 31 | manager.createContext(gssServerName, spnegoOid, null, GSSCredential.DEFAULT_LIFETIME); 32 | gssContext.requestMutualAuth(true); 33 | gssContext.requestCredDeleg(true); 34 | 35 | // Generate the SPNEGO token 36 | byte[] token = new byte[0]; 37 | token = gssContext.initSecContext(token, 0, token.length); 38 | return token; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /code/client/client-lib/src/main/proto/broker.proto: -------------------------------------------------------------------------------- 1 | ../../../../../broker-server/src/main/proto/broker.proto -------------------------------------------------------------------------------- /code/client/hadoop-connector/src/main/java/com/google/cloud/broker/client/hadoop/fs/BrokerDelegationTokenBinding.java: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Google LLC 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // You may obtain a copy of the License at 5 | // http://www.apache.org/licenses/LICENSE-2.0 6 | // Unless required by applicable law or agreed to in writing, software 7 | // distributed under the License is distributed on an "AS IS" BASIS, 8 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | // See the License for the specific language governing permissions and 10 | // limitations under the License. 11 | 12 | package com.google.cloud.broker.client.hadoop.fs; 13 | 14 | import com.google.cloud.hadoop.fs.gcs.auth.AbstractDelegationTokenBinding; 15 | import com.google.cloud.hadoop.util.AccessTokenProvider; 16 | import java.io.IOException; 17 | import org.apache.hadoop.io.Text; 18 | import org.apache.hadoop.security.UserGroupInformation; 19 | import org.apache.hadoop.security.token.delegation.web.DelegationTokenIdentifier; 20 | 21 | public class BrokerDelegationTokenBinding extends AbstractDelegationTokenBinding { 22 | 23 | public BrokerDelegationTokenBinding() { 24 | super(BrokerTokenIdentifier.KIND); 25 | } 26 | 27 | @Override 28 | public AccessTokenProvider deployUnbonded() throws IOException { 29 | return new BrokerAccessTokenProvider(getService()); 30 | } 31 | 32 | @Override 33 | public AccessTokenProvider bindToTokenIdentifier(DelegationTokenIdentifier retrievedIdentifier) 34 | throws IOException { 35 | return new BrokerAccessTokenProvider(getService(), (BrokerTokenIdentifier) retrievedIdentifier); 36 | } 37 | 38 | @Override 39 | public DelegationTokenIdentifier createTokenIdentifier() throws IOException { 40 | return createEmptyIdentifier(); 41 | } 42 | 43 | @Override 44 | public DelegationTokenIdentifier createTokenIdentifier(Text renewer) throws IOException { 45 | UserGroupInformation ugi = UserGroupInformation.getCurrentUser(); 46 | String user = ugi.getUserName(); 47 | Text owner = new Text(user); 48 | Text realUser = null; 49 | if (ugi.getRealUser() != null) { 50 | realUser = new Text(ugi.getRealUser().getUserName()); 51 | } 52 | return new BrokerTokenIdentifier( 53 | getFileSystem().getConf(), owner, renewer, realUser, getService()); 54 | } 55 | 56 | @Override 57 | public DelegationTokenIdentifier createEmptyIdentifier() { 58 | return new BrokerTokenIdentifier(); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /code/client/hadoop-connector/src/main/java/com/google/cloud/broker/client/hadoop/fs/Utils.java: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Google LLC 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // You may obtain a copy of the License at 5 | // http://www.apache.org/licenses/LICENSE-2.0 6 | // Unless required by applicable law or agreed to in writing, software 7 | // distributed under the License is distributed on an "AS IS" BASIS, 8 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | // See the License for the specific language governing permissions and 10 | // limitations under the License. 11 | 12 | package com.google.cloud.broker.client.hadoop.fs; 13 | 14 | import com.google.cloud.broker.client.connect.BrokerServerInfo; 15 | import org.apache.hadoop.conf.Configuration; 16 | import org.apache.hadoop.io.Text; 17 | 18 | public class Utils { 19 | 20 | public static final String CONFIG_ACCESS_BOUNDARY_ENABLED = 21 | "gcp.token.broker.access.boundary.enabled"; 22 | public static final String CONFIG_URI = "gcp.token.broker.uri"; 23 | public static final String CONFIG_PRINCIPAL = "gcp.token.broker.kerberos.principal"; 24 | public static final String CONFIG_CERTIFICATE = "gcp.token.broker.tls.certificate"; 25 | public static final String CONFIG_CERTIFICATE_PATH = "gcp.token.broker.tls.certificate.path"; 26 | public static final String CONFIG_USE_APP_DEFAULT_CREDENTIALS = 27 | "gcp.token.broker.use.app.default.credentials"; 28 | 29 | public static String getTarget(Configuration config, Text service) { 30 | boolean accessBoundaryEnabled = 31 | Boolean.parseBoolean(config.get(CONFIG_ACCESS_BOUNDARY_ENABLED, "false")); 32 | if (accessBoundaryEnabled) { 33 | String uri = service.toString(); 34 | if (uri.startsWith("gs://")) { 35 | uri = "//storage.googleapis.com/projects/_/buckets/" + uri.substring(5); 36 | } 37 | return uri; 38 | } else { 39 | return ""; 40 | } 41 | } 42 | 43 | public static BrokerServerInfo getBrokerDetailsFromConfig(Configuration config) { 44 | return new BrokerServerInfo( 45 | config.get(CONFIG_URI), 46 | config.get(CONFIG_PRINCIPAL), 47 | config.get(CONFIG_CERTIFICATE), 48 | config.get(CONFIG_CERTIFICATE_PATH)); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /code/client/hadoop-connector/src/main/java/com/google/cloud/broker/client/hadoop/fs/commands/CancelSessionToken.java: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Google LLC 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // You may obtain a copy of the License at 5 | // http://www.apache.org/licenses/LICENSE-2.0 6 | // Unless required by applicable law or agreed to in writing, software 7 | // distributed under the License is distributed on an "AS IS" BASIS, 8 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | // See the License for the specific language governing permissions and 10 | // limitations under the License. 11 | 12 | package com.google.cloud.broker.client.hadoop.fs.commands; 13 | 14 | import com.google.cloud.broker.client.hadoop.fs.BrokerTokenIdentifier; 15 | import com.google.cloud.broker.client.hadoop.fs.BrokerTokenRenewer; 16 | import java.io.IOException; 17 | import org.apache.hadoop.conf.Configuration; 18 | import org.apache.hadoop.io.Text; 19 | import org.apache.hadoop.security.token.Token; 20 | import picocli.CommandLine; 21 | import picocli.CommandLine.Command; 22 | import picocli.CommandLine.Option; 23 | 24 | @Command(name = "CancelSessionToken", description = "Retrieves an Oauth2 access token") 25 | public class CancelSessionToken implements Runnable { 26 | 27 | @Option( 28 | names = {"-u", "--uri"}, 29 | required = true, 30 | description = "GCS URI for the access token") 31 | private String uri; 32 | 33 | @Option( 34 | names = {"-f", "--session-token-file"}, 35 | required = true, 36 | description = "File that contains the session token to be canceled") 37 | private String file; 38 | 39 | @Option( 40 | names = {"-h", "--help"}, 41 | usageHelp = true, 42 | description = "Display this help") 43 | boolean help; 44 | 45 | private void sendRequest(Configuration config, String sessionToken) { 46 | String bucket = CommandUtils.extractBucketNameFromGcsUri(uri); 47 | Text service = new Text(bucket); 48 | Token token = CommandUtils.getTokenBTI(sessionToken, service); 49 | BrokerTokenRenewer renewer = new BrokerTokenRenewer(); 50 | try { 51 | renewer.cancel(token, config); 52 | } catch (IOException e) { 53 | throw new RuntimeException(e); 54 | } 55 | System.out.println("\n> Session token successfully canceled\n"); 56 | } 57 | 58 | @Override 59 | public void run() { 60 | Configuration config = new Configuration(); 61 | CommandUtils.showConfig(config); 62 | String sessionToken = CommandUtils.readSessionToken(file); 63 | sendRequest(config, sessionToken); 64 | } 65 | 66 | public static void main(String[] args) { 67 | CommandLine.run(new CancelSessionToken(), args); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /code/client/hadoop-connector/src/main/java/com/google/cloud/broker/client/hadoop/fs/commands/RenewSessionToken.java: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Google LLC 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // You may obtain a copy of the License at 5 | // http://www.apache.org/licenses/LICENSE-2.0 6 | // Unless required by applicable law or agreed to in writing, software 7 | // distributed under the License is distributed on an "AS IS" BASIS, 8 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | // See the License for the specific language governing permissions and 10 | // limitations under the License. 11 | 12 | package com.google.cloud.broker.client.hadoop.fs.commands; 13 | 14 | import com.google.cloud.broker.client.hadoop.fs.BrokerTokenIdentifier; 15 | import com.google.cloud.broker.client.hadoop.fs.BrokerTokenRenewer; 16 | import java.io.IOException; 17 | import org.apache.hadoop.conf.Configuration; 18 | import org.apache.hadoop.io.Text; 19 | import org.apache.hadoop.security.token.Token; 20 | import picocli.CommandLine; 21 | import picocli.CommandLine.Command; 22 | import picocli.CommandLine.Option; 23 | 24 | @Command(name = "RenewSessionToken", description = "Retrieves an Oauth2 access token") 25 | public class RenewSessionToken implements Runnable { 26 | 27 | @Option( 28 | names = {"-u", "--uri"}, 29 | required = true, 30 | description = "GCS URI for the access token") 31 | private String uri; 32 | 33 | @Option( 34 | names = {"-f", "--session-token-file"}, 35 | required = true, 36 | description = "File that contains the session token to be renewed") 37 | private String file; 38 | 39 | @Option( 40 | names = {"-h", "--help"}, 41 | usageHelp = true, 42 | description = "Display this help") 43 | boolean help; 44 | 45 | private void sendRequest(Configuration config, String sessionToken) { 46 | String bucket = CommandUtils.extractBucketNameFromGcsUri(uri); 47 | Text service = new Text(bucket); 48 | Token token = CommandUtils.getTokenBTI(sessionToken, service); 49 | BrokerTokenRenewer renewer = new BrokerTokenRenewer(); 50 | try { 51 | renewer.renew(token, config); 52 | } catch (IOException e) { 53 | throw new RuntimeException(e); 54 | } 55 | System.out.println("\n> Session token successfully renewed\n"); 56 | } 57 | 58 | @Override 59 | public void run() { 60 | Configuration config = new Configuration(); 61 | CommandUtils.showConfig(config); 62 | String sessionToken = CommandUtils.readSessionToken(file); 63 | sendRequest(config, sessionToken); 64 | } 65 | 66 | public static void main(String[] args) { 67 | CommandLine.run(new RenewSessionToken(), args); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /code/client/hadoop-connector/src/main/resources/META-INF/services/org.apache.hadoop.security.token.TokenIdentifier: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Google LLC 2 | # Licensed under the Apache License, Version 2.0 (the "License"); 3 | # you may not use this file except in compliance with the License. 4 | # You may obtain a copy of the License at 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # Unless required by applicable law or agreed to in writing, software 7 | # distributed under the License is distributed on an "AS IS" BASIS, 8 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | # See the License for the specific language governing permissions and 10 | # limitations under the License. 11 | 12 | com.google.cloud.broker.client.hadoop.fs.BrokerTokenIdentifier -------------------------------------------------------------------------------- /code/client/hadoop-connector/src/main/resources/META-INF/services/org.apache.hadoop.security.token.TokenRenewer: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Google LLC 2 | # Licensed under the Apache License, Version 2.0 (the "License"); 3 | # you may not use this file except in compliance with the License. 4 | # You may obtain a copy of the License at 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # Unless required by applicable law or agreed to in writing, software 7 | # distributed under the License is distributed on an "AS IS" BASIS, 8 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | # See the License for the specific language governing permissions and 10 | # limitations under the License. 11 | 12 | com.google.cloud.broker.client.hadoop.fs.BrokerTokenRenewer -------------------------------------------------------------------------------- /code/client/hadoop-connector/src/test/java/com/google/cloud/broker/client/hadoop/fs/BrokerDelegationTokenBindingTest.java: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Google LLC 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // You may obtain a copy of the License at 5 | // http://www.apache.org/licenses/LICENSE-2.0 6 | // Unless required by applicable law or agreed to in writing, software 7 | // distributed under the License is distributed on an "AS IS" BASIS, 8 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | // See the License for the specific language governing permissions and 10 | // limitations under the License. 11 | 12 | package com.google.cloud.broker.client.hadoop.fs; 13 | 14 | import static org.junit.Assert.*; 15 | 16 | import java.io.IOException; 17 | import org.junit.Test; 18 | 19 | public class BrokerDelegationTokenBindingTest { 20 | 21 | @Test 22 | public void testDeployUnbonded() { 23 | BrokerDelegationTokenBinding binding = new BrokerDelegationTokenBinding(); 24 | try { 25 | BrokerAccessTokenProvider provider = (BrokerAccessTokenProvider) binding.deployUnbonded(); 26 | // TODO... 27 | } catch (IOException e) { 28 | fail(); 29 | } 30 | } 31 | 32 | @Test 33 | public void testCreateTokenIdentifier() { 34 | BrokerDelegationTokenBinding binding = new BrokerDelegationTokenBinding(); 35 | BrokerTokenIdentifier identifier = (BrokerTokenIdentifier) binding.createEmptyIdentifier(); 36 | // TODO... 37 | } 38 | 39 | @Test 40 | public void testCreateEmptyIdentifier() { 41 | BrokerDelegationTokenBinding binding = new BrokerDelegationTokenBinding(); 42 | try { 43 | BrokerTokenIdentifier identifier = (BrokerTokenIdentifier) binding.createTokenIdentifier(); 44 | // TODO... 45 | } catch (IOException e) { 46 | fail(); 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /code/client/hadoop-connector/src/test/java/com/google/cloud/broker/client/utils/GrpcUtilsTest.java: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Google LLC 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // You may obtain a copy of the License at 5 | // http://www.apache.org/licenses/LICENSE-2.0 6 | // Unless required by applicable law or agreed to in writing, software 7 | // distributed under the License is distributed on an "AS IS" BASIS, 8 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | // See the License for the specific language governing permissions and 10 | // limitations under the License. 11 | 12 | package com.google.cloud.broker.client.utils; 13 | 14 | import static org.junit.Assert.*; 15 | 16 | import com.google.cloud.broker.apps.brokerserver.protobuf.BrokerGrpc; 17 | import io.grpc.ManagedChannel; 18 | import io.grpc.internal.testing.TestUtils; 19 | import java.io.IOException; 20 | import java.security.cert.CertificateException; 21 | import java.security.cert.X509Certificate; 22 | import java.util.Base64; 23 | import org.junit.Test; 24 | 25 | public class GrpcUtilsTest { 26 | 27 | @Test 28 | public void testManagedChannelAuthority() { 29 | ManagedChannel channel = GrpcUtils.newManagedChannel("testhost", 8888, false, null); 30 | assertEquals("testhost:8888", channel.authority()); 31 | } 32 | 33 | @Test 34 | public void testManagedChannelTLSSuccess() { 35 | String certificate; 36 | try { 37 | X509Certificate[] trustedCaCerts = {TestUtils.loadX509Cert("ca.pem")}; 38 | certificate = 39 | "-----BEGIN CERTIFICATE-----\n" 40 | + Base64.getEncoder().encodeToString(trustedCaCerts[0].getEncoded()) 41 | + "\n" 42 | + "-----END CERTIFICATE-----"; 43 | } catch (CertificateException | IOException e) { 44 | throw new RuntimeException(e); 45 | } 46 | ManagedChannel channel = GrpcUtils.newManagedChannel("testhost", 8888, true, certificate); 47 | // TODO: Verify that the certificate is correctly assigned to the channel 48 | } 49 | 50 | @Test 51 | public void testManagedChannelTLSInvalidCertificate() { 52 | try { 53 | GrpcUtils.newManagedChannel("testhost", 8888, true, "aaaa"); 54 | fail(); 55 | } catch (IllegalArgumentException e) { 56 | assertEquals("The provided certificate for the broker service is invalid", e.getMessage()); 57 | } 58 | } 59 | 60 | @Test 61 | public void testNewStub() { 62 | ManagedChannel channel = GrpcUtils.newManagedChannel("testhost", 8888, false, null); 63 | BrokerGrpc.BrokerBlockingStub stub = GrpcUtils.newStub(channel); 64 | assertEquals(channel, stub.getChannel()); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /code/core/src/main/java/com/google/cloud/broker/authentication/AuthorizationHeaderServerInterceptor.java: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Google LLC 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // You may obtain a copy of the License at 5 | // http://www.apache.org/licenses/LICENSE-2.0 6 | // Unless required by applicable law or agreed to in writing, software 7 | // distributed under the License is distributed on an "AS IS" BASIS, 8 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | // See the License for the specific language governing permissions and 10 | // limitations under the License. 11 | 12 | package com.google.cloud.broker.authentication; 13 | 14 | import io.grpc.*; 15 | 16 | public class AuthorizationHeaderServerInterceptor implements ServerInterceptor { 17 | 18 | private static final Metadata.Key BROKER_AUTHORIZATION_METADATA_KEY = 19 | Metadata.Key.of("broker-authorization", Metadata.ASCII_STRING_MARSHALLER); 20 | public static final Context.Key BROKER_AUTHORIZATION_CONTEXT_KEY = 21 | Context.key("BrokerAuthorizationHeader"); 22 | 23 | @Override 24 | public ServerCall.Listener interceptCall( 25 | ServerCall serverCall, 26 | Metadata metadata, 27 | ServerCallHandler serverCallHandler) { 28 | String authorizationHeader = metadata.get(BROKER_AUTHORIZATION_METADATA_KEY); 29 | Context ctx = 30 | Context.current().withValue(BROKER_AUTHORIZATION_CONTEXT_KEY, authorizationHeader); 31 | return Contexts.interceptCall(ctx, serverCall, metadata, serverCallHandler); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /code/core/src/main/java/com/google/cloud/broker/authentication/backends/AbstractAuthenticationBackend.java: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Google LLC 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // You may obtain a copy of the License at 5 | // http://www.apache.org/licenses/LICENSE-2.0 6 | // Unless required by applicable law or agreed to in writing, software 7 | // distributed under the License is distributed on an "AS IS" BASIS, 8 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | // See the License for the specific language governing permissions and 10 | // limitations under the License. 11 | 12 | package com.google.cloud.broker.authentication.backends; 13 | 14 | import com.google.cloud.broker.authentication.AuthorizationHeaderServerInterceptor; 15 | import com.google.cloud.broker.settings.AppSettings; 16 | import com.google.cloud.broker.utils.InstanceUtils; 17 | import org.slf4j.MDC; 18 | 19 | public abstract class AbstractAuthenticationBackend { 20 | 21 | private static AbstractAuthenticationBackend instance; 22 | public static final String AUTHENTICATED_USER = "authenticatedUser"; 23 | 24 | public static AbstractAuthenticationBackend getInstance() { 25 | String className = AppSettings.getInstance().getString(AppSettings.AUTHENTICATION_BACKEND); 26 | if (instance == null || !className.equals(instance.getClass().getCanonicalName())) { 27 | instance = (AbstractAuthenticationBackend) InstanceUtils.invokeConstructor(className); 28 | } 29 | return instance; 30 | } 31 | 32 | public String authenticateUser() { 33 | String authorizationHeader = 34 | AuthorizationHeaderServerInterceptor.BROKER_AUTHORIZATION_CONTEXT_KEY.get(); 35 | String authenticatedUser = authenticateUser(authorizationHeader); 36 | MDC.put(AUTHENTICATED_USER, authenticatedUser); 37 | return authenticatedUser; 38 | } 39 | 40 | public abstract String authenticateUser(String authorizationHeader); 41 | } 42 | -------------------------------------------------------------------------------- /code/core/src/main/java/com/google/cloud/broker/caching/local/LocalCache.java: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Google LLC 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // You may obtain a copy of the License at 5 | // http://www.apache.org/licenses/LICENSE-2.0 6 | // Unless required by applicable law or agreed to in writing, software 7 | // distributed under the License is distributed on an "AS IS" BASIS, 8 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | // See the License for the specific language governing permissions and 10 | // limitations under the License. 11 | 12 | package com.google.cloud.broker.caching.local; 13 | 14 | import java.util.concurrent.TimeUnit; 15 | import net.jodah.expiringmap.ExpirationPolicy; 16 | import net.jodah.expiringmap.ExpiringMap; 17 | 18 | public class LocalCache { 19 | 20 | private static ExpiringMap cache = 21 | ExpiringMap.builder().variableExpiration().build(); 22 | 23 | public static Object get(String key) { 24 | return cache.get(key); 25 | } 26 | 27 | public static void set(String key, Object value) { 28 | cache.put(key, value); 29 | } 30 | 31 | public static void set(String key, Object value, int expireIn) { 32 | cache.put(key, value, ExpirationPolicy.CREATED, expireIn, TimeUnit.SECONDS); 33 | } 34 | 35 | public static void delete(String key) { 36 | cache.remove(key); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /code/core/src/main/java/com/google/cloud/broker/caching/remote/AbstractRemoteCache.java: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Google LLC 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // You may obtain a copy of the License at 5 | // http://www.apache.org/licenses/LICENSE-2.0 6 | // Unless required by applicable law or agreed to in writing, software 7 | // distributed under the License is distributed on an "AS IS" BASIS, 8 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | // See the License for the specific language governing permissions and 10 | // limitations under the License. 11 | 12 | package com.google.cloud.broker.caching.remote; 13 | 14 | import com.google.cloud.broker.checks.CheckResult; 15 | import com.google.cloud.broker.settings.AppSettings; 16 | import com.google.cloud.broker.utils.InstanceUtils; 17 | import java.util.concurrent.locks.Lock; 18 | 19 | public abstract class AbstractRemoteCache { 20 | 21 | private static AbstractRemoteCache instance; 22 | 23 | public abstract byte[] get(String key); 24 | 25 | public abstract void set(String key, byte[] value); 26 | 27 | public abstract void set(String key, byte[] value, int expireIn); // "expireIn" in seconds 28 | 29 | public abstract void delete(String key); 30 | 31 | public abstract Lock acquireLock(String lockName); 32 | 33 | public abstract CheckResult checkConnection(); 34 | 35 | public static AbstractRemoteCache getInstance() { 36 | String className = AppSettings.getInstance().getString(AppSettings.REMOTE_CACHE); 37 | if (instance == null || !className.equals(instance.getClass().getCanonicalName())) { 38 | instance = (AbstractRemoteCache) InstanceUtils.invokeConstructor(className); 39 | } 40 | return instance; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /code/core/src/main/java/com/google/cloud/broker/caching/remote/DummyCache.java: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Google LLC 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // You may obtain a copy of the License at 5 | // http://www.apache.org/licenses/LICENSE-2.0 6 | // Unless required by applicable law or agreed to in writing, software 7 | // distributed under the License is distributed on an "AS IS" BASIS, 8 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | // See the License for the specific language governing permissions and 10 | // limitations under the License. 11 | 12 | package com.google.cloud.broker.caching.remote; 13 | 14 | import com.google.cloud.broker.checks.CheckResult; 15 | import java.util.concurrent.TimeUnit; 16 | import java.util.concurrent.locks.Condition; 17 | import java.util.concurrent.locks.Lock; 18 | 19 | /** 20 | * Dummy caching backend that does not actually cache anything. Use only for testing. Do NOT use in 21 | * production! 22 | */ 23 | public class DummyCache extends AbstractRemoteCache { 24 | 25 | @Override 26 | public byte[] get(String key) { 27 | return null; 28 | } 29 | 30 | @Override 31 | public void set(String key, byte[] value) {} 32 | 33 | @Override 34 | public void set(String key, byte[] value, int expireIn) {} 35 | 36 | @Override 37 | public void delete(String key) {} 38 | 39 | @Override 40 | public Lock acquireLock(String lockName) { 41 | return new NoOpLock(); 42 | } 43 | 44 | @Override 45 | public CheckResult checkConnection() { 46 | return new CheckResult(true); 47 | } 48 | 49 | public static class NoOpLock implements Lock { 50 | 51 | @Override 52 | public void lock() {} 53 | 54 | @Override 55 | public void lockInterruptibly() throws InterruptedException {} 56 | 57 | @Override 58 | public boolean tryLock() { 59 | return true; 60 | } 61 | 62 | @Override 63 | public boolean tryLock(long time, TimeUnit unit) throws InterruptedException { 64 | return true; 65 | } 66 | 67 | @Override 68 | public void unlock() {} 69 | 70 | @Override 71 | public Condition newCondition() { 72 | throw new UnsupportedOperationException(); 73 | } 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /code/core/src/main/java/com/google/cloud/broker/checks/CheckResult.java: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Google LLC 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // You may obtain a copy of the License at 5 | // http://www.apache.org/licenses/LICENSE-2.0 6 | // Unless required by applicable law or agreed to in writing, software 7 | // distributed under the License is distributed on an "AS IS" BASIS, 8 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | // See the License for the specific language governing permissions and 10 | // limitations under the License. 11 | 12 | package com.google.cloud.broker.checks; 13 | 14 | public class CheckResult { 15 | 16 | private boolean success; 17 | private String message; 18 | private String type; 19 | 20 | public CheckResult(boolean success) { 21 | this(success, null); 22 | } 23 | 24 | public CheckResult(boolean success, String message) { 25 | this.success = success; 26 | this.message = message; 27 | } 28 | 29 | public boolean isSuccess() { 30 | return success; 31 | } 32 | 33 | public String getMessage() { 34 | return message; 35 | } 36 | 37 | public String getType() { 38 | return type; 39 | } 40 | 41 | public void setType(String type) { 42 | this.type = type; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /code/core/src/main/java/com/google/cloud/broker/checks/SystemCheck.java: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Google LLC 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // You may obtain a copy of the License at 5 | // http://www.apache.org/licenses/LICENSE-2.0 6 | // Unless required by applicable law or agreed to in writing, software 7 | // distributed under the License is distributed on an "AS IS" BASIS, 8 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | // See the License for the specific language governing permissions and 10 | // limitations under the License. 11 | 12 | package com.google.cloud.broker.checks; 13 | 14 | import com.google.cloud.broker.caching.remote.AbstractRemoteCache; 15 | import com.google.cloud.broker.database.backends.AbstractDatabaseBackend; 16 | import com.google.cloud.broker.encryption.backends.AbstractEncryptionBackend; 17 | import java.lang.invoke.MethodHandles; 18 | import java.util.ArrayList; 19 | import java.util.List; 20 | import org.slf4j.Logger; 21 | import org.slf4j.LoggerFactory; 22 | 23 | public class SystemCheck { 24 | 25 | private static final Logger logger = 26 | LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); 27 | private static List results = new ArrayList<>(); 28 | 29 | public static void runChecks() { 30 | // Check the database connection 31 | CheckResult dbResult = AbstractDatabaseBackend.getInstance().checkConnection(); 32 | dbResult.setType("Database backend"); 33 | results.add(dbResult); 34 | 35 | // Check the cache connection 36 | CheckResult cacheResult = AbstractRemoteCache.getInstance().checkConnection(); 37 | cacheResult.setType("Cache backend"); 38 | results.add(cacheResult); 39 | 40 | // Check the encryption backend 41 | CheckResult encryptionResult = AbstractEncryptionBackend.getInstance().checkConnection(); 42 | encryptionResult.setType("Encryption backend"); 43 | results.add(encryptionResult); 44 | 45 | // Collate all the potential check failures together 46 | StringBuilder sb = new StringBuilder(); 47 | for (CheckResult result : results) { 48 | if (!result.isSuccess()) { 49 | sb.append(String.format("* Failure: %s\n\n%s\n\n", result.getType(), result.getMessage())); 50 | } 51 | } 52 | 53 | // Raise exception if any failures were found 54 | if (sb.length() > 0) { 55 | throw new IllegalStateException("System check failures!\n\n" + sb.toString()); 56 | } 57 | 58 | logger.info("System checks passed"); 59 | } 60 | 61 | public static void main(String[] args) { 62 | runChecks(); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /code/core/src/main/java/com/google/cloud/broker/database/DatabaseObjectNotFound.java: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Google LLC 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // You may obtain a copy of the License at 5 | // http://www.apache.org/licenses/LICENSE-2.0 6 | // Unless required by applicable law or agreed to in writing, software 7 | // distributed under the License is distributed on an "AS IS" BASIS, 8 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | // See the License for the specific language governing permissions and 10 | // limitations under the License. 11 | 12 | package com.google.cloud.broker.database; 13 | 14 | public class DatabaseObjectNotFound extends Exception { 15 | 16 | public DatabaseObjectNotFound(String message) { 17 | super(message); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /code/core/src/main/java/com/google/cloud/broker/database/InitializeDatabase.java: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Google LLC 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // You may obtain a copy of the License at 5 | // http://www.apache.org/licenses/LICENSE-2.0 6 | // Unless required by applicable law or agreed to in writing, software 7 | // distributed under the License is distributed on an "AS IS" BASIS, 8 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | // See the License for the specific language governing permissions and 10 | // limitations under the License. 11 | 12 | package com.google.cloud.broker.database; 13 | 14 | import com.google.cloud.broker.database.backends.AbstractDatabaseBackend; 15 | 16 | public class InitializeDatabase { 17 | 18 | public static void main(String[] args) { 19 | AbstractDatabaseBackend.getInstance().initializeDatabase(); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /code/core/src/main/java/com/google/cloud/broker/database/backends/AbstractDatabaseBackend.java: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Google LLC 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // You may obtain a copy of the License at 5 | // http://www.apache.org/licenses/LICENSE-2.0 6 | // Unless required by applicable law or agreed to in writing, software 7 | // distributed under the License is distributed on an "AS IS" BASIS, 8 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | // See the License for the specific language governing permissions and 10 | // limitations under the License. 11 | 12 | package com.google.cloud.broker.database.backends; 13 | 14 | import com.google.cloud.broker.checks.CheckResult; 15 | import com.google.cloud.broker.database.DatabaseObjectNotFound; 16 | import com.google.cloud.broker.database.models.Model; 17 | import com.google.cloud.broker.settings.AppSettings; 18 | import com.google.cloud.broker.utils.InstanceUtils; 19 | import java.util.List; 20 | 21 | public abstract class AbstractDatabaseBackend { 22 | 23 | private static AbstractDatabaseBackend instance; 24 | 25 | public abstract List getAll(Class modelClass); 26 | 27 | public abstract Model get(Class modelClass, String objectId) throws DatabaseObjectNotFound; 28 | 29 | public abstract void save(Model model); 30 | 31 | public abstract void delete(Model model); 32 | 33 | public int deleteExpiredItems(Class modelClass, String field, Long cutoffTime) { 34 | return deleteExpiredItems(modelClass, field, cutoffTime, null); 35 | } 36 | 37 | public abstract int deleteExpiredItems( 38 | Class modelClass, String field, Long cutoffTime, Integer numItems); 39 | 40 | public abstract void initializeDatabase(); 41 | 42 | public abstract CheckResult checkConnection(); 43 | 44 | public static AbstractDatabaseBackend getInstance() { 45 | String className = AppSettings.getInstance().getString(AppSettings.DATABASE_BACKEND); 46 | if (instance == null || !className.equals(instance.getClass().getCanonicalName())) { 47 | instance = (AbstractDatabaseBackend) InstanceUtils.invokeConstructor(className); 48 | } 49 | return instance; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /code/core/src/main/java/com/google/cloud/broker/database/models/Model.java: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Google LLC 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // You may obtain a copy of the License at 5 | // http://www.apache.org/licenses/LICENSE-2.0 6 | // Unless required by applicable law or agreed to in writing, software 7 | // distributed under the License is distributed on an "AS IS" BASIS, 8 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | // See the License for the specific language governing permissions and 10 | // limitations under the License. 11 | 12 | package com.google.cloud.broker.database.models; 13 | 14 | import java.lang.reflect.InvocationTargetException; 15 | import java.lang.reflect.Method; 16 | import java.util.Map; 17 | 18 | public abstract class Model { 19 | 20 | public abstract Map toMap(); 21 | 22 | public abstract void setDBId(String id); 23 | 24 | public abstract String getDBId(); 25 | 26 | public static Model fromMap(Class klass, Map map) { 27 | Method method; 28 | try { 29 | method = klass.getMethod("fromMap", Map.class); 30 | } catch (NoSuchMethodException e) { 31 | throw new RuntimeException(e); 32 | } 33 | try { 34 | return (Model) method.invoke(null, map); 35 | } catch (IllegalAccessException | InvocationTargetException e) { 36 | throw new RuntimeException(e); 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /code/core/src/main/java/com/google/cloud/broker/encryption/backends/AbstractEncryptionBackend.java: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Google LLC 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // You may obtain a copy of the License at 5 | // http://www.apache.org/licenses/LICENSE-2.0 6 | // Unless required by applicable law or agreed to in writing, software 7 | // distributed under the License is distributed on an "AS IS" BASIS, 8 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | // See the License for the specific language governing permissions and 10 | // limitations under the License. 11 | 12 | package com.google.cloud.broker.encryption.backends; 13 | 14 | import com.google.cloud.broker.checks.CheckResult; 15 | import com.google.cloud.broker.settings.AppSettings; 16 | import com.google.cloud.broker.utils.InstanceUtils; 17 | 18 | public abstract class AbstractEncryptionBackend { 19 | 20 | private static AbstractEncryptionBackend instance; 21 | 22 | public abstract byte[] decrypt(byte[] cipherText); 23 | 24 | public abstract byte[] encrypt(byte[] plainText); 25 | 26 | public abstract CheckResult checkConnection(); 27 | 28 | public static AbstractEncryptionBackend getInstance() { 29 | String className = AppSettings.getInstance().getString(AppSettings.ENCRYPTION_BACKEND); 30 | if (instance == null || !className.equals(instance.getClass().getCanonicalName())) { 31 | instance = (AbstractEncryptionBackend) InstanceUtils.invokeConstructor(className); 32 | } 33 | return instance; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /code/core/src/main/java/com/google/cloud/broker/encryption/backends/DummyEncryptionBackend.java: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Google LLC 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // You may obtain a copy of the License at 5 | // http://www.apache.org/licenses/LICENSE-2.0 6 | // Unless required by applicable law or agreed to in writing, software 7 | // distributed under the License is distributed on an "AS IS" BASIS, 8 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | // See the License for the specific language governing permissions and 10 | // limitations under the License. 11 | 12 | package com.google.cloud.broker.encryption.backends; 13 | 14 | import com.google.cloud.broker.checks.CheckResult; 15 | 16 | /** 17 | * Dummy encryption backend that does not encrypt nor decrypt anything. Use only for testing. Do NOT 18 | * use in production! 19 | */ 20 | public class DummyEncryptionBackend extends AbstractEncryptionBackend { 21 | 22 | @Override 23 | public byte[] decrypt(byte[] cipherText) { 24 | return cipherText; 25 | } 26 | 27 | @Override 28 | public byte[] encrypt(byte[] plainText) { 29 | return plainText; 30 | } 31 | 32 | @Override 33 | public CheckResult checkConnection() { 34 | return new CheckResult(true); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /code/core/src/main/java/com/google/cloud/broker/oauth/OauthClientSecretsLoader.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.google.cloud.broker.oauth; 18 | 19 | import com.google.api.client.googleapis.auth.oauth2.GoogleClientSecrets; 20 | import com.google.api.client.json.JsonFactory; 21 | import com.google.api.client.json.jackson2.JacksonFactory; 22 | import com.google.cloud.broker.settings.AppSettings; 23 | import com.typesafe.config.ConfigException; 24 | import java.io.*; 25 | 26 | public class OauthClientSecretsLoader { 27 | 28 | public static GoogleClientSecrets getSecrets() { 29 | try { 30 | String jsonPath = 31 | AppSettings.getInstance().getString(AppSettings.OAUTH_CLIENT_SECRET_JSON_PATH); 32 | // Load the JSON file if provided 33 | File secretJson = new java.io.File(jsonPath); 34 | JsonFactory jsonFactory = JacksonFactory.getDefaultInstance(); 35 | try { 36 | InputStream in = new FileInputStream(secretJson); 37 | return GoogleClientSecrets.load(jsonFactory, new InputStreamReader(in)); 38 | } catch (IOException e) { 39 | throw new RuntimeException(e); 40 | } 41 | } catch (ConfigException.Missing e) { 42 | // The JSON path setting was not provided, so we try with other settings 43 | try { 44 | String clientId = AppSettings.getInstance().getString(AppSettings.OAUTH_CLIENT_ID); 45 | String clientSecret = AppSettings.getInstance().getString(AppSettings.OAUTH_CLIENT_SECRET); 46 | 47 | // Fall back to using the provided ID and secret 48 | GoogleClientSecrets.Details details = new GoogleClientSecrets.Details(); 49 | details.setClientId(clientId); 50 | details.setClientSecret(clientSecret); 51 | GoogleClientSecrets clientSecrets = new GoogleClientSecrets(); 52 | clientSecrets.setWeb(details); 53 | return clientSecrets; 54 | } catch (ConfigException.Missing ex) { 55 | throw new RuntimeException( 56 | String.format( 57 | "OAuth misconfigured. Please provide settings `%s` or `%s` and `%s`", 58 | AppSettings.OAUTH_CLIENT_SECRET_JSON_PATH, 59 | AppSettings.OAUTH_CLIENT_ID, 60 | AppSettings.OAUTH_CLIENT_SECRET)); 61 | } 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /code/core/src/main/java/com/google/cloud/broker/oauth/RefreshToken.java: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Google LLC 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // You may obtain a copy of the License at 5 | // http://www.apache.org/licenses/LICENSE-2.0 6 | // Unless required by applicable law or agreed to in writing, software 7 | // distributed under the License is distributed on an "AS IS" BASIS, 8 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | // See the License for the specific language governing permissions and 10 | // limitations under the License. 11 | 12 | package com.google.cloud.broker.oauth; 13 | 14 | import com.fasterxml.jackson.annotation.JsonProperty; 15 | import com.google.cloud.broker.database.models.Model; 16 | import com.google.cloud.broker.utils.TimeUtils; 17 | import java.util.HashMap; 18 | import java.util.Map; 19 | 20 | public class RefreshToken extends Model { 21 | 22 | private String id; // GSuite email address (e.g. alice@example.com) 23 | private byte[] value; // The actual OAuth refresh token (Recommendation: encrypt this value) 24 | private Long creationTime; // The time when the object was created (in milliseconds) 25 | 26 | public RefreshToken( 27 | @JsonProperty("id") String id, 28 | @JsonProperty("value") byte[] value, 29 | @JsonProperty("creationTime") Long creationTime) { 30 | setId(id); 31 | setValue(value); 32 | setCreationTime( 33 | (creationTime == null) ? Long.valueOf(TimeUtils.currentTimeMillis()) : creationTime); 34 | } 35 | 36 | @Override 37 | public Map toMap() { 38 | HashMap map = new HashMap(); 39 | map.put("id", id); 40 | map.put("value", value); 41 | map.put("creationTime", creationTime); 42 | return map; 43 | } 44 | 45 | public static Model fromMap(Map map) { 46 | return new RefreshToken( 47 | (String) map.get("id"), (byte[]) map.get("value"), (Long) map.get("creationTime")); 48 | } 49 | 50 | public void setDBId(String id) { 51 | setId(id); 52 | } 53 | 54 | public String getDBId() { 55 | return getId(); 56 | } 57 | 58 | public String getId() { 59 | return id; 60 | } 61 | 62 | public void setId(String id) { 63 | this.id = id; 64 | } 65 | 66 | public byte[] getValue() { 67 | return value; 68 | } 69 | 70 | public void setValue(byte[] value) { 71 | this.value = value; 72 | } 73 | 74 | public Long getCreationTime() { 75 | return creationTime; 76 | } 77 | 78 | public void setCreationTime(Long creationTime) { 79 | this.creationTime = creationTime; 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /code/core/src/main/java/com/google/cloud/broker/secretmanager/DownloadSecrets.java: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Google LLC 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // You may obtain a copy of the License at 5 | // http://www.apache.org/licenses/LICENSE-2.0 6 | // Unless required by applicable law or agreed to in writing, software 7 | // distributed under the License is distributed on an "AS IS" BASIS, 8 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | // See the License for the specific language governing permissions and 10 | // limitations under the License. 11 | 12 | package com.google.cloud.broker.secretmanager; 13 | 14 | public class DownloadSecrets { 15 | 16 | public static void main(String[] args) { 17 | SecretManager.downloadSecrets(); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /code/core/src/main/java/com/google/cloud/broker/usermapping/AbstractUserMapper.java: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Google LLC 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // You may obtain a copy of the License at 5 | // http://www.apache.org/licenses/LICENSE-2.0 6 | // Unless required by applicable law or agreed to in writing, software 7 | // distributed under the License is distributed on an "AS IS" BASIS, 8 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | // See the License for the specific language governing permissions and 10 | // limitations under the License. 11 | 12 | package com.google.cloud.broker.usermapping; 13 | 14 | import com.google.cloud.broker.settings.AppSettings; 15 | import com.google.cloud.broker.utils.InstanceUtils; 16 | 17 | public abstract class AbstractUserMapper { 18 | 19 | private static AbstractUserMapper instance; 20 | 21 | public static AbstractUserMapper getInstance() { 22 | String className = AppSettings.getInstance().getString(AppSettings.USER_MAPPER); 23 | if (instance == null || !className.equals(instance.getClass().getCanonicalName())) { 24 | instance = (AbstractUserMapper) InstanceUtils.invokeConstructor(className); 25 | } 26 | return instance; 27 | } 28 | 29 | public abstract String map(String name) throws IllegalArgumentException; 30 | } 31 | -------------------------------------------------------------------------------- /code/core/src/main/java/com/google/cloud/broker/usermapping/MapUser.java: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Google LLC 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // You may obtain a copy of the License at 5 | // http://www.apache.org/licenses/LICENSE-2.0 6 | // Unless required by applicable law or agreed to in writing, software 7 | // distributed under the License is distributed on an "AS IS" BASIS, 8 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | // See the License for the specific language governing permissions and 10 | // limitations under the License. 11 | 12 | package com.google.cloud.broker.usermapping; 13 | 14 | import com.google.cloud.broker.validation.EmailValidation; 15 | import java.lang.invoke.MethodHandles; 16 | import org.slf4j.Logger; 17 | import org.slf4j.LoggerFactory; 18 | 19 | public class MapUser { 20 | 21 | private static final Logger logger = 22 | LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); 23 | 24 | public static void main(String[] args) { 25 | if (args.length == 1) { 26 | String email = AbstractUserMapper.getInstance().map(args[0]); 27 | EmailValidation.validateEmail(email); 28 | logger.info(email); 29 | } else { 30 | logger.error("This command requires one argument."); 31 | System.exit(1); 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /code/core/src/main/java/com/google/cloud/broker/utils/CloudStorageUtils.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.google.cloud.broker.utils; 18 | 19 | import com.google.auth.oauth2.GoogleCredentials; 20 | import com.google.cloud.storage.Storage; 21 | import com.google.cloud.storage.StorageOptions; 22 | import java.io.IOException; 23 | 24 | public class CloudStorageUtils { 25 | 26 | public static final String GCS_API = "https://www.googleapis.com/auth/devstorage.read_write"; 27 | 28 | public static GoogleCredentials getCloudStorageCredentials() { 29 | try { 30 | return GoogleCredentials.getApplicationDefault().createScoped(GCS_API); 31 | } catch (IOException e) { 32 | throw new RuntimeException(e); 33 | } 34 | } 35 | 36 | public static Storage getCloudStorageClient() { 37 | GoogleCredentials credentials = getCloudStorageCredentials(); 38 | return getCloudStorageClient(credentials); 39 | } 40 | 41 | public static Storage getCloudStorageClient(GoogleCredentials credentials) { 42 | return StorageOptions.newBuilder().setCredentials(credentials).build().getService(); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /code/core/src/main/java/com/google/cloud/broker/utils/Constants.java: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Google LLC 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // You may obtain a copy of the License at 5 | // http://www.apache.org/licenses/LICENSE-2.0 6 | // Unless required by applicable law or agreed to in writing, software 7 | // distributed under the License is distributed on an "AS IS" BASIS, 8 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | // See the License for the specific language governing permissions and 10 | // limitations under the License. 11 | 12 | package com.google.cloud.broker.utils; 13 | 14 | public class Constants { 15 | 16 | public static final String APPLICATION_NAME = "gcp-token-broker"; 17 | } 18 | -------------------------------------------------------------------------------- /code/core/src/main/java/com/google/cloud/broker/utils/InstanceUtils.java: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Google LLC 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // You may obtain a copy of the License at 5 | // http://www.apache.org/licenses/LICENSE-2.0 6 | // Unless required by applicable law or agreed to in writing, software 7 | // distributed under the License is distributed on an "AS IS" BASIS, 8 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | // See the License for the specific language governing permissions and 10 | // limitations under the License. 11 | 12 | package com.google.cloud.broker.utils; 13 | 14 | import java.lang.reflect.Constructor; 15 | import java.lang.reflect.InvocationTargetException; 16 | 17 | public class InstanceUtils { 18 | 19 | public static Object invokeConstructor(String className) { 20 | try { 21 | Class c = Class.forName(className); 22 | Constructor constructor = c.getConstructor(); 23 | return constructor.newInstance(); 24 | } catch (InvocationTargetException e) { 25 | Throwable cause = e.getCause(); 26 | if (cause == null) { 27 | throw new RuntimeException(e); 28 | } else { 29 | throw new RuntimeException(cause); 30 | } 31 | } catch (Exception e) { 32 | throw new RuntimeException(e); 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /code/core/src/main/java/com/google/cloud/broker/utils/TimeUtils.java: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Google LLC 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // You may obtain a copy of the License at 5 | // http://www.apache.org/licenses/LICENSE-2.0 6 | // Unless required by applicable law or agreed to in writing, software 7 | // distributed under the License is distributed on an "AS IS" BASIS, 8 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | // See the License for the specific language governing permissions and 10 | // limitations under the License. 11 | 12 | package com.google.cloud.broker.utils; 13 | 14 | public final class TimeUtils { 15 | 16 | public static long currentTimeMillis() { 17 | return System.currentTimeMillis(); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /code/core/src/main/java/com/google/cloud/broker/validation/EmailValidation.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.google.cloud.broker.validation; 18 | 19 | import java.util.regex.Matcher; 20 | import java.util.regex.Pattern; 21 | 22 | public class EmailValidation { 23 | 24 | public static void validateEmail(String email) { 25 | Pattern parser = Pattern.compile("([a-zA-Z0-9\\.-]+)@([a-zA-Z0-9\\.-]+)"); 26 | Matcher match = parser.matcher(email); 27 | if (!match.matches()) { 28 | throw new IllegalArgumentException("Invalid email: " + email); 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /code/core/src/test/java/com/google/cloud/broker/authentication/backends/AbstractAuthenticationBackendTest.java: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Google LLC 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // You may obtain a copy of the License at 5 | // http://www.apache.org/licenses/LICENSE-2.0 6 | // Unless required by applicable law or agreed to in writing, software 7 | // distributed under the License is distributed on an "AS IS" BASIS, 8 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | // See the License for the specific language governing permissions and 10 | // limitations under the License. 11 | 12 | package com.google.cloud.broker.authentication.backends; 13 | 14 | import static org.junit.Assert.*; 15 | 16 | import com.google.cloud.broker.settings.AppSettings; 17 | import com.google.cloud.broker.settings.SettingsOverride; 18 | import java.util.Map; 19 | import org.junit.Test; 20 | 21 | public class AbstractAuthenticationBackendTest { 22 | 23 | @Test 24 | public void testGetInstance() { 25 | try (SettingsOverride override = 26 | SettingsOverride.apply( 27 | Map.of(AppSettings.AUTHENTICATION_BACKEND, "com.example.DoesNotExist"))) { 28 | try { 29 | AbstractAuthenticationBackend.getInstance(); 30 | fail(); 31 | } catch (RuntimeException e) { 32 | assertEquals("java.lang.ClassNotFoundException: com.example.DoesNotExist", e.getMessage()); 33 | } 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /code/core/src/test/java/com/google/cloud/broker/caching/remote/AbstractRemoteCacheTest.java: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Google LLC 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // You may obtain a copy of the License at 5 | // http://www.apache.org/licenses/LICENSE-2.0 6 | // Unless required by applicable law or agreed to in writing, software 7 | // distributed under the License is distributed on an "AS IS" BASIS, 8 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | // See the License for the specific language governing permissions and 10 | // limitations under the License. 11 | 12 | package com.google.cloud.broker.caching.remote; 13 | 14 | import static org.junit.Assert.*; 15 | 16 | import com.google.cloud.broker.settings.AppSettings; 17 | import com.google.cloud.broker.settings.SettingsOverride; 18 | import java.util.Map; 19 | import org.junit.Test; 20 | 21 | public class AbstractRemoteCacheTest { 22 | 23 | @Test 24 | public void testGetInstance() { 25 | try (SettingsOverride override = 26 | SettingsOverride.apply(Map.of(AppSettings.REMOTE_CACHE, "com.example.DoesNotExist"))) { 27 | try { 28 | AbstractRemoteCache.getInstance(); 29 | fail(); 30 | } catch (RuntimeException e) { 31 | assertEquals("java.lang.ClassNotFoundException: com.example.DoesNotExist", e.getMessage()); 32 | } 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /code/core/src/test/java/com/google/cloud/broker/database/backends/AbstractDatabaseBackendTest.java: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Google LLC 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // You may obtain a copy of the License at 5 | // http://www.apache.org/licenses/LICENSE-2.0 6 | // Unless required by applicable law or agreed to in writing, software 7 | // distributed under the License is distributed on an "AS IS" BASIS, 8 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | // See the License for the specific language governing permissions and 10 | // limitations under the License. 11 | 12 | package com.google.cloud.broker.database.backends; 13 | 14 | import static org.junit.Assert.*; 15 | 16 | import com.google.cloud.broker.settings.AppSettings; 17 | import com.google.cloud.broker.settings.SettingsOverride; 18 | import java.util.Map; 19 | import org.junit.Test; 20 | 21 | public class AbstractDatabaseBackendTest { 22 | 23 | @Test 24 | public void testGetInstance() { 25 | try (SettingsOverride override = 26 | SettingsOverride.apply(Map.of(AppSettings.DATABASE_BACKEND, "com.example.DoesNotExist"))) { 27 | try { 28 | AbstractDatabaseBackend.getInstance(); 29 | fail(); 30 | } catch (RuntimeException e) { 31 | assertEquals("java.lang.ClassNotFoundException: com.example.DoesNotExist", e.getMessage()); 32 | } 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /code/core/src/test/java/com/google/cloud/broker/encryption/backends/AbstractEncryptionBackendTest.java: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Google LLC 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // You may obtain a copy of the License at 5 | // http://www.apache.org/licenses/LICENSE-2.0 6 | // Unless required by applicable law or agreed to in writing, software 7 | // distributed under the License is distributed on an "AS IS" BASIS, 8 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | // See the License for the specific language governing permissions and 10 | // limitations under the License. 11 | 12 | package com.google.cloud.broker.encryption.backends; 13 | 14 | import static org.junit.Assert.*; 15 | 16 | import com.google.cloud.broker.settings.AppSettings; 17 | import com.google.cloud.broker.settings.SettingsOverride; 18 | import java.util.Map; 19 | import org.junit.Test; 20 | 21 | public class AbstractEncryptionBackendTest { 22 | 23 | @Test 24 | public void testGetInstance() { 25 | try (SettingsOverride override = 26 | SettingsOverride.apply( 27 | Map.of(AppSettings.ENCRYPTION_BACKEND, "com.example.DoesNotExist"))) { 28 | try { 29 | AbstractEncryptionBackend.getInstance(); 30 | fail(); 31 | } catch (RuntimeException e) { 32 | assertEquals("java.lang.ClassNotFoundException: com.example.DoesNotExist", e.getMessage()); 33 | } 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /code/core/src/test/java/com/google/cloud/broker/oauth/RefreshTokenTest.java: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Google LLC 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // You may obtain a copy of the License at 5 | // http://www.apache.org/licenses/LICENSE-2.0 6 | // Unless required by applicable law or agreed to in writing, software 7 | // distributed under the License is distributed on an "AS IS" BASIS, 8 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | // See the License for the specific language governing permissions and 10 | // limitations under the License. 11 | 12 | package com.google.cloud.broker.oauth; 13 | 14 | import static org.junit.Assert.*; 15 | 16 | import com.google.cloud.broker.database.models.Model; 17 | import java.util.HashMap; 18 | import org.junit.Test; 19 | 20 | public class RefreshTokenTest { 21 | 22 | // TODO: testToMap 23 | 24 | @Test 25 | public void testFromMap() { 26 | HashMap values = new HashMap(); 27 | values.put("id", "alice@example.com"); 28 | values.put("creationTime", 2222222222222L); 29 | values.put("value", "xyz".getBytes()); 30 | 31 | RefreshToken token = (RefreshToken) Model.fromMap(RefreshToken.class, values); 32 | assertEquals("alice@example.com", token.getId()); 33 | assertEquals(2222222222222L, token.getCreationTime().longValue()); 34 | assertArrayEquals("xyz".getBytes(), token.getValue()); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /code/core/src/test/java/com/google/cloud/broker/settings/SettingsOverride.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.google.cloud.broker.settings; 18 | 19 | import com.typesafe.config.Config; 20 | import com.typesafe.config.ConfigFactory; 21 | import java.util.HashMap; 22 | import java.util.Map; 23 | import org.junit.rules.TestRule; 24 | import org.junit.runner.Description; 25 | import org.junit.runners.model.Statement; 26 | 27 | public class SettingsOverride implements TestRule, AutoCloseable { 28 | 29 | private Map newSettingsMap; 30 | private Config backupConfig; 31 | 32 | public SettingsOverride() { 33 | this(new HashMap<>()); 34 | } 35 | 36 | public SettingsOverride(Map newSettingsMap) { 37 | this.newSettingsMap = newSettingsMap; 38 | // Keep a backup of the old settings 39 | backupConfig = AppSettings.getInstance(); 40 | } 41 | 42 | /** Called when used as a jUnit Rule. */ 43 | @Override 44 | public Statement apply(Statement statement, Description description) { 45 | return new Statement() { 46 | @Override 47 | public void evaluate() throws Throwable { 48 | // Override the settings 49 | override(); 50 | try { 51 | // Execute the test 52 | statement.evaluate(); 53 | } finally { 54 | // Restore the old settings 55 | restore(); 56 | } 57 | } 58 | }; 59 | } 60 | 61 | private void override() { 62 | // Replace settings' instance with a new, temporary one 63 | AppSettings.setInstance( 64 | ConfigFactory.parseMap(newSettingsMap).withFallback(AppSettings.getInstance())); 65 | } 66 | 67 | private void restore() { 68 | // Restore the old settings 69 | AppSettings.setInstance(backupConfig); 70 | } 71 | 72 | /** To be used as an AutoCloseable in a try() clause. */ 73 | public static SettingsOverride apply(Map newSettingsMap) { 74 | SettingsOverride settingsOverride = new SettingsOverride(newSettingsMap); 75 | settingsOverride.override(); 76 | return settingsOverride; 77 | } 78 | 79 | /** Automatically triggered at the end of a try() clause. */ 80 | @Override 81 | public void close() { 82 | restore(); 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /code/extensions/caching/cloud-datastore/src/main/java/com/google/cloud/broker/caching/remote/DatastoreCacheCleanup.java: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Google LLC 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // You may obtain a copy of the License at 5 | // http://www.apache.org/licenses/LICENSE-2.0 6 | // Unless required by applicable law or agreed to in writing, software 7 | // distributed under the License is distributed on an "AS IS" BASIS, 8 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | // See the License for the specific language governing permissions and 10 | // limitations under the License. 11 | 12 | package com.google.cloud.broker.caching.remote; 13 | 14 | import java.lang.invoke.MethodHandles; 15 | import org.slf4j.Logger; 16 | import org.slf4j.LoggerFactory; 17 | 18 | public class DatastoreCacheCleanup { 19 | 20 | private static final Class klass = MethodHandles.lookup().lookupClass(); 21 | private static final Logger logger = LoggerFactory.getLogger(klass); 22 | 23 | public static void main(String[] args) { 24 | Integer limit = null; 25 | if (args.length > 0) { 26 | limit = Integer.parseInt(args[0]); 27 | } 28 | CloudDatastoreCache cache = new CloudDatastoreCache(); 29 | int numDeletedItems = cache.deleteExpiredItems(limit); 30 | logger.info(klass.getSimpleName() + " - Deleted expired item(s): " + numDeletedItems); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /code/extensions/caching/redis/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 15 | 16 | 18 | 4.0.0 19 | 20 | 21 | com.google.cloud.broker 22 | broker-parent 23 | 0.10.5 24 | ../../../../pom.xml 25 | 26 | 27 | cache-backend-redis 28 | 29 | Redis cache backend for the GCP Token Broker 30 | 31 | 32 | 33 | com.google.cloud.broker 34 | broker-core 35 | ${project.parent.version} 36 | provided 37 | 38 | 39 | org.redisson 40 | redisson 41 | ${org.redisson.version} 42 | 43 | 44 | 45 | 46 | com.google.cloud.broker 47 | broker-core 48 | ${project.parent.version} 49 | test-jar 50 | test 51 | 52 | 53 | 54 | 55 | 56 | 57 | maven-assembly-plugin 58 | ${maven-assembly-plugin.version} 59 | 60 | 61 | package 62 | 63 | single 64 | 65 | 66 | 67 | jar-with-dependencies 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | -------------------------------------------------------------------------------- /code/extensions/database/cloud-datastore/src/test/java/com/google/cloud/broker/database/backends/Foo.java: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Google LLC 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // You may obtain a copy of the License at 5 | // http://www.apache.org/licenses/LICENSE-2.0 6 | // Unless required by applicable law or agreed to in writing, software 7 | // distributed under the License is distributed on an "AS IS" BASIS, 8 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | // See the License for the specific language governing permissions and 10 | // limitations under the License. 11 | 12 | package com.google.cloud.broker.database.backends; 13 | 14 | import com.fasterxml.jackson.annotation.JsonProperty; 15 | import com.google.cloud.broker.database.models.Model; 16 | import com.google.common.collect.ImmutableList; 17 | import java.util.HashMap; 18 | import java.util.List; 19 | import java.util.Map; 20 | 21 | public class Foo extends Model { 22 | 23 | private String id; 24 | private byte[] byteVal; 25 | private Long longVal; 26 | private List stringList; 27 | 28 | public Foo( 29 | @JsonProperty("id") String id, 30 | @JsonProperty("byteVal") byte[] byteVal, 31 | @JsonProperty("longVal") Long longVal, 32 | @JsonProperty("longVal") List stringList) { 33 | setId(id); 34 | setByteVal(byteVal); 35 | setLongVal(longVal); 36 | setStringList(stringList); 37 | } 38 | 39 | @Override 40 | public Map toMap() { 41 | HashMap map = new HashMap(); 42 | map.put("id", id); 43 | map.put("byteVal", byteVal); 44 | map.put("longVal", longVal); 45 | map.put("stringList", stringList); 46 | return map; 47 | } 48 | 49 | public static Model fromMap(Map map) { 50 | return new Foo( 51 | (String) map.get("id"), 52 | (byte[]) map.get("byteVal"), 53 | (Long) map.get("longVal"), 54 | (List) map.get("stringList")); 55 | } 56 | 57 | public void setDBId(String id) { 58 | setId(id); 59 | } 60 | 61 | public String getDBId() { 62 | return getId(); 63 | } 64 | 65 | public String getId() { 66 | return id; 67 | } 68 | 69 | public void setId(String id) { 70 | this.id = id; 71 | } 72 | 73 | public byte[] getByteVal() { 74 | return byteVal; 75 | } 76 | 77 | public void setByteVal(byte[] byteVal) { 78 | this.byteVal = byteVal; 79 | } 80 | 81 | public Long getLongVal() { 82 | return longVal; 83 | } 84 | 85 | public void setLongVal(Long longVal) { 86 | this.longVal = longVal; 87 | } 88 | 89 | public List getStringList() { 90 | return stringList; 91 | } 92 | 93 | public void setStringList(List stringList) { 94 | this.stringList = ImmutableList.copyOf(stringList); 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /code/extensions/database/jdbc/src/test/java/com/google/cloud/broker/database/backends/MariaDBBackendTest.java: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Google LLC 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // You may obtain a copy of the License at 5 | // http://www.apache.org/licenses/LICENSE-2.0 6 | // Unless required by applicable law or agreed to in writing, software 7 | // distributed under the License is distributed on an "AS IS" BASIS, 8 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | // See the License for the specific language governing permissions and 10 | // limitations under the License. 11 | 12 | package com.google.cloud.broker.database.backends; 13 | 14 | import com.google.cloud.broker.database.DatabaseObjectNotFound; 15 | import com.google.cloud.broker.settings.AppSettings; 16 | import com.google.cloud.broker.settings.SettingsOverride; 17 | import java.util.Map; 18 | import org.junit.*; 19 | 20 | public class MariaDBBackendTest extends JDBCBackendTest { 21 | 22 | private static JDBCBackend backend; 23 | 24 | @ClassRule 25 | public static SettingsOverride settingsOverride = 26 | new SettingsOverride( 27 | Map.of( 28 | AppSettings.DATABASE_JDBC_URL, 29 | "jdbc:mariadb://localhost:3306/broker?user=testuser&password=UNSECURE-PASSWORD")); 30 | 31 | @BeforeClass 32 | public static void setupClass() { 33 | backend = new JDBCBackend(); 34 | } 35 | 36 | @Before 37 | public void setup() { 38 | JDBCBackendTest.setup(backend); 39 | } 40 | 41 | @After 42 | public void teardown() { 43 | JDBCBackendTest.teardown(backend); 44 | } 45 | 46 | @Test 47 | public void testInitializeDatabase() { 48 | JDBCBackendTest.initializeDatabase(backend); 49 | } 50 | 51 | @Test 52 | public void testSaveNew() { 53 | JDBCBackendTest.saveNew(backend); 54 | } 55 | 56 | @Test 57 | public void testUpdate() { 58 | JDBCBackendTest.update(backend); 59 | } 60 | 61 | @Test 62 | public void testSaveWithoutID() { 63 | JDBCBackendTest.saveWithoutID(backend); 64 | } 65 | 66 | @Test 67 | public void testGet() throws DatabaseObjectNotFound { 68 | JDBCBackendTest.get(backend); 69 | } 70 | 71 | @Test 72 | public void testGetNotExist() { 73 | JDBCBackendTest.getNotExist(backend); 74 | } 75 | 76 | @Test 77 | public void testDelete() { 78 | JDBCBackendTest.delete(backend); 79 | } 80 | 81 | @Test 82 | public void testDeleteExpiredItems() { 83 | JDBCBackendTest.deleteExpiredItems(backend, false); 84 | } 85 | 86 | @Test 87 | public void testDeleteExpiredItemsWithLimit() { 88 | JDBCBackendTest.deleteExpiredItems(backend, true); 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /code/extensions/database/jdbc/src/test/java/com/google/cloud/broker/database/backends/PostgreSQLBackendTest.java: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Google LLC 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // You may obtain a copy of the License at 5 | // http://www.apache.org/licenses/LICENSE-2.0 6 | // Unless required by applicable law or agreed to in writing, software 7 | // distributed under the License is distributed on an "AS IS" BASIS, 8 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | // See the License for the specific language governing permissions and 10 | // limitations under the License. 11 | 12 | package com.google.cloud.broker.database.backends; 13 | 14 | import com.google.cloud.broker.database.DatabaseObjectNotFound; 15 | import com.google.cloud.broker.settings.AppSettings; 16 | import com.google.cloud.broker.settings.SettingsOverride; 17 | import java.util.Map; 18 | import org.junit.*; 19 | 20 | public class PostgreSQLBackendTest extends JDBCBackendTest { 21 | 22 | private static JDBCBackend backend; 23 | 24 | @ClassRule 25 | public static SettingsOverride settingsOverride = 26 | new SettingsOverride( 27 | Map.of( 28 | AppSettings.DATABASE_JDBC_URL, 29 | "jdbc:postgresql:broker?user=testuser&password=UNSECURE-PASSWORD")); 30 | 31 | @BeforeClass 32 | public static void setupClass() { 33 | backend = new JDBCBackend(); 34 | } 35 | 36 | @Before 37 | public void setup() { 38 | JDBCBackendTest.setup(backend); 39 | } 40 | 41 | @After 42 | public void teardown() { 43 | JDBCBackendTest.teardown(backend); 44 | } 45 | 46 | @Test 47 | public void testInitializeDatabase() { 48 | JDBCBackendTest.initializeDatabase(backend); 49 | } 50 | 51 | @Test 52 | public void testSaveNew() { 53 | JDBCBackendTest.saveNew(backend); 54 | } 55 | 56 | @Test 57 | public void testUpdate() { 58 | JDBCBackendTest.update(backend); 59 | } 60 | 61 | @Test 62 | public void testSaveWithoutID() { 63 | JDBCBackendTest.saveWithoutID(backend); 64 | } 65 | 66 | @Test 67 | public void testGet() throws DatabaseObjectNotFound { 68 | JDBCBackendTest.get(backend); 69 | } 70 | 71 | @Test 72 | public void testGetNotExist() { 73 | JDBCBackendTest.getNotExist(backend); 74 | } 75 | 76 | @Test 77 | public void testDelete() { 78 | JDBCBackendTest.delete(backend); 79 | } 80 | 81 | @Test 82 | public void testDeleteExpiredItems() { 83 | JDBCBackendTest.deleteExpiredItems(backend, false); 84 | } 85 | 86 | @Test 87 | public void testDeleteExpiredItemsWithLimit() { 88 | JDBCBackendTest.deleteExpiredItems(backend, true); 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /code/extensions/database/jdbc/src/test/java/com/google/cloud/broker/database/backends/SQLiteBackendTest.java: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Google LLC 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // You may obtain a copy of the License at 5 | // http://www.apache.org/licenses/LICENSE-2.0 6 | // Unless required by applicable law or agreed to in writing, software 7 | // distributed under the License is distributed on an "AS IS" BASIS, 8 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | // See the License for the specific language governing permissions and 10 | // limitations under the License. 11 | 12 | package com.google.cloud.broker.database.backends; 13 | 14 | import com.google.cloud.broker.database.DatabaseObjectNotFound; 15 | import com.google.cloud.broker.settings.AppSettings; 16 | import com.google.cloud.broker.settings.SettingsOverride; 17 | import java.util.Map; 18 | import org.junit.*; 19 | 20 | public class SQLiteBackendTest extends JDBCBackendTest { 21 | 22 | private static JDBCBackend backend; 23 | 24 | @ClassRule 25 | public static SettingsOverride settingsOverride = 26 | new SettingsOverride(Map.of(AppSettings.DATABASE_JDBC_URL, "jdbc:sqlite::memory:")); 27 | 28 | @BeforeClass 29 | public static void setupClass() { 30 | backend = new JDBCBackend(); 31 | } 32 | 33 | @Before 34 | public void setup() { 35 | JDBCBackendTest.setup(backend); 36 | } 37 | 38 | @After 39 | public void teardown() { 40 | JDBCBackendTest.teardown(backend); 41 | } 42 | 43 | @Test 44 | public void testInitializeDatabase() { 45 | JDBCBackendTest.initializeDatabase(backend); 46 | } 47 | 48 | @Test 49 | public void testSaveNew() { 50 | JDBCBackendTest.saveNew(backend); 51 | } 52 | 53 | @Test 54 | public void testUpdate() { 55 | JDBCBackendTest.update(backend); 56 | } 57 | 58 | @Test 59 | public void testSaveWithoutID() { 60 | JDBCBackendTest.saveWithoutID(backend); 61 | } 62 | 63 | @Test 64 | public void testGet() throws DatabaseObjectNotFound { 65 | JDBCBackendTest.get(backend); 66 | } 67 | 68 | @Test 69 | public void testGetNotExist() { 70 | JDBCBackendTest.getNotExist(backend); 71 | } 72 | 73 | @Test 74 | public void testDelete() { 75 | JDBCBackendTest.delete(backend); 76 | } 77 | 78 | @Test 79 | public void testDeleteExpiredItems() { 80 | JDBCBackendTest.deleteExpiredItems(backend, false); 81 | } 82 | 83 | @Test 84 | public void testDeleteExpiredItemsWithLimit() { 85 | JDBCBackendTest.deleteExpiredItems(backend, true); 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /code/extensions/encryption/cloud-kms/src/main/java/com/google/cloud/broker/encryption/GenerateDEK.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.google.cloud.broker.encryption; 18 | 19 | import com.google.cloud.broker.encryption.backends.CloudKMSBackend; 20 | import com.google.cloud.broker.settings.AppSettings; 21 | import java.lang.invoke.MethodHandles; 22 | import org.slf4j.Logger; 23 | import org.slf4j.LoggerFactory; 24 | 25 | /** Command-line utility that generates a new data encryption key (DEK) and stores it in GCS */ 26 | public class GenerateDEK { 27 | 28 | private static final Logger logger = 29 | LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); 30 | 31 | public static void main(String[] args) { 32 | String dekUri = null; 33 | String kekUri = null; 34 | if (args.length == 0) { 35 | dekUri = AppSettings.getInstance().getString(AppSettings.ENCRYPTION_DEK_URI); 36 | kekUri = AppSettings.getInstance().getString(AppSettings.ENCRYPTION_KEK_URI); 37 | } else if (args.length == 2) { 38 | dekUri = args[0]; 39 | kekUri = args[1]; 40 | } else { 41 | logger.error("Invalid parameters"); 42 | System.exit(1); 43 | } 44 | 45 | logger.info("Generating DEK..."); 46 | logger.info("Wrapping with KEK `" + kekUri + "`..."); 47 | logger.info("Writing to `" + dekUri + "`..."); 48 | try { 49 | CloudKMSBackend.generateAndWriteKeyset(dekUri, kekUri); 50 | } catch (Exception e) { 51 | logger.error("Failed to generate and write DEK"); 52 | e.printStackTrace(System.err); 53 | System.exit(1); 54 | } 55 | logger.info("Done."); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /code/extensions/encryption/cloud-kms/src/main/java/com/google/cloud/broker/encryption/backends/keyset/CloudStorageKeysetManager.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.google.cloud.broker.encryption.backends.keyset; 18 | 19 | import com.google.cloud.WriteChannel; 20 | import com.google.cloud.broker.utils.CloudStorageUtils; 21 | import com.google.cloud.storage.BlobId; 22 | import com.google.cloud.storage.BlobInfo; 23 | import com.google.crypto.tink.JsonKeysetReader; 24 | import com.google.crypto.tink.JsonKeysetWriter; 25 | import com.google.crypto.tink.proto.EncryptedKeyset; 26 | import com.google.crypto.tink.proto.Keyset; 27 | import java.io.IOException; 28 | import java.io.OutputStream; 29 | import java.net.URI; 30 | import java.net.URISyntaxException; 31 | import java.nio.channels.Channels; 32 | 33 | /** KeysetManager that reads and writes DEKs from Cloud Storage. */ 34 | public class CloudStorageKeysetManager extends KeysetManager { 35 | 36 | private URI dekUri; 37 | 38 | CloudStorageKeysetManager(String dekUri) { 39 | try { 40 | this.dekUri = new URI(dekUri); 41 | } catch (URISyntaxException e) { 42 | throw new RuntimeException(e); 43 | } 44 | } 45 | 46 | @Override 47 | public Keyset read() throws IOException { 48 | throw new UnsupportedOperationException(); 49 | } 50 | 51 | @Override 52 | public EncryptedKeyset readEncrypted() throws IOException { 53 | BlobId blobId = BlobId.of(dekUri.getAuthority(), dekUri.getPath().substring(1)); 54 | return JsonKeysetReader.withBytes( 55 | CloudStorageUtils.getCloudStorageClient().readAllBytes(blobId)) 56 | .readEncrypted(); 57 | } 58 | 59 | @Override 60 | public void write(Keyset keyset) throws IOException { 61 | throw new UnsupportedOperationException(); 62 | } 63 | 64 | @Override 65 | public void write(EncryptedKeyset keyset) throws IOException { 66 | BlobId blobId = BlobId.of(dekUri.getAuthority(), dekUri.getPath().substring(1)); 67 | WriteChannel wc = 68 | CloudStorageUtils.getCloudStorageClient().writer(BlobInfo.newBuilder(blobId).build()); 69 | OutputStream os = Channels.newOutputStream(wc); 70 | JsonKeysetWriter.withOutputStream(os).write(keyset); 71 | os.close(); 72 | wc.close(); 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /code/extensions/encryption/cloud-kms/src/main/java/com/google/cloud/broker/encryption/backends/keyset/FilesystemKeysetManager.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.google.cloud.broker.encryption.backends.keyset; 18 | 19 | import com.google.crypto.tink.JsonKeysetReader; 20 | import com.google.crypto.tink.JsonKeysetWriter; 21 | import com.google.crypto.tink.proto.EncryptedKeyset; 22 | import com.google.crypto.tink.proto.Keyset; 23 | import java.io.IOException; 24 | import java.nio.file.Path; 25 | import java.nio.file.Paths; 26 | 27 | /** KeysetManager that reads and writes DEKs from the local filesystem. */ 28 | public class FilesystemKeysetManager extends KeysetManager { 29 | 30 | private Path dekUri; 31 | 32 | FilesystemKeysetManager(String dekUri) { 33 | this.dekUri = Paths.get(dekUri); 34 | } 35 | 36 | @Override 37 | public Keyset read() throws IOException { 38 | throw new UnsupportedOperationException(); 39 | } 40 | 41 | @Override 42 | public EncryptedKeyset readEncrypted() throws IOException { 43 | return JsonKeysetReader.withPath(dekUri).readEncrypted(); 44 | } 45 | 46 | @Override 47 | public void write(Keyset keyset) throws IOException { 48 | throw new UnsupportedOperationException(); 49 | } 50 | 51 | @Override 52 | public void write(EncryptedKeyset keyset) throws IOException { 53 | JsonKeysetWriter.withPath(dekUri).write(keyset); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /code/extensions/encryption/cloud-kms/src/main/java/com/google/cloud/broker/encryption/backends/keyset/KeysetManager.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.google.cloud.broker.encryption.backends.keyset; 18 | 19 | import com.google.crypto.tink.KeysetReader; 20 | import com.google.crypto.tink.KeysetWriter; 21 | 22 | public abstract class KeysetManager implements KeysetWriter, KeysetReader {} 23 | -------------------------------------------------------------------------------- /code/extensions/encryption/cloud-kms/src/main/java/com/google/cloud/broker/encryption/backends/keyset/KeysetUtils.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.google.cloud.broker.encryption.backends.keyset; 18 | 19 | public class KeysetUtils { 20 | 21 | public static KeysetManager getKeysetManager(String dekUri) { 22 | if (dekUri.startsWith("gs://")) { 23 | return new CloudStorageKeysetManager(dekUri); 24 | } else if (dekUri.startsWith("file://")) { 25 | return new FilesystemKeysetManager(dekUri.substring(7)); 26 | } else { 27 | throw new RuntimeException("Invalid DEK URI: " + dekUri); 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /code/extensions/encryption/cloud-kms/src/test/java/com/google/cloud/broker/encryption/backends/CloudKMSBackendTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Google LLC 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.google.cloud.broker.encryption.backends; 18 | 19 | import static org.junit.Assert.*; 20 | 21 | import com.google.cloud.broker.settings.AppSettings; 22 | import com.google.cloud.broker.settings.SettingsOverride; 23 | import java.util.Arrays; 24 | import java.util.Map; 25 | import org.junit.ClassRule; 26 | import org.junit.Test; 27 | 28 | public class CloudKMSBackendTest { 29 | 30 | private static String projectId = AppSettings.getInstance().getString(AppSettings.GCP_PROJECT); 31 | 32 | @ClassRule 33 | public static SettingsOverride settingsOverride = 34 | new SettingsOverride( 35 | Map.of( 36 | AppSettings.ENCRYPTION_KEK_URI, 37 | "projects/" 38 | + projectId 39 | + "/locations/global/keyRings/testkeyring/cryptoKeys/testkey", 40 | AppSettings.ENCRYPTION_DEK_URI, "gs://" + projectId + "-testbucket/testkey.json")); 41 | 42 | /** Encryption backend shall encrypt and correctly decrypt a given plaintext */ 43 | @Test 44 | public void testEncryptAndDecrypt() { 45 | CloudKMSBackend aead = new CloudKMSBackend(); 46 | byte[] plainText = "test string".getBytes(); 47 | byte[] cipherText = aead.encrypt(plainText); 48 | assertFalse(Arrays.equals(plainText, cipherText)); 49 | byte[] decrypted = aead.decrypt(cipherText); 50 | assertArrayEquals(plainText, decrypted); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /docs/concepts/authorizer.md: -------------------------------------------------------------------------------- 1 | # Authorizer 2 | 3 | The Authorizer is a Web UI that walks users through an OAuth 2.0 flow to collect OAuth refresh tokens. 4 | 5 | It is necessary for your users to use the Authorizer if you choose to use the [`RefreshTokenProvider`](providers.md#refresh-token-provider). 6 | 7 | When users complete the OAuth flow, the Authorizer obtains a refresh token, [encrypts](encryption.md) it, 8 | and stores it in the [database](database.md). At that point the user is fully authorized to use the broker service. 9 | It is only necessary for each user to go through the flow once. 10 | 11 | The Authorizer application serves three endpoints: 12 | 13 | - `/`: Landing page for the Authorizer app. 14 | - `/google/login`: Redirects the user to the Google login page. 15 | - `/google/oauth2callback`: Receives the OAuth 2.0 authorization code from Google, then uses it to 16 | obtain a refresh token for the authenticated Google user. The refresh token is then encrypted 17 | and stored in the database. 18 | 19 | ## Running the Authorizer 20 | 21 | To run the Authorizer: 22 | 23 | 1. Retrieve the JAR file for the Authorizer package from [Maven Central](https://search.maven.org/search?q=g:com.google.cloud.broker%20AND%20a:authorizer): 24 | ```xml 25 | com.google.cloud.broker 26 | authorizer 27 | ``` 28 | 2. Retrieve all the JAR files from Maven Central for the [encryption backend](encryption.md#encryption-backends) and 29 | [database backend](database.md#database-backends)) that you wish to use for your deployment. 30 | 3. Place all the JAR files in the `CLASSPATH`. 31 | 4. Create an `application.conf` file with the [settings](settings.md) for your environment. 32 | 5. [Initialize the database](database.md#database-initialization). 33 | 6. Run the following command: 34 | 35 | ```shell 36 | CONFIG_FILE=//application.conf java com.google.cloud.broker.apps.authorizer.Authorizer 37 | ``` 38 | -------------------------------------------------------------------------------- /docs/concepts/broker-server.md: -------------------------------------------------------------------------------- 1 | # Broker server 2 | 3 | The broker server is the core component of the broker architecture. It accepts [gRPC](https://grpc.io/) requests from 4 | clients and serves four different endpoints: 5 | 6 | - `GetAccessToken`: Returns a GCP access token. Can be called either using [direct authentication](authentication.md#direct-authentication), 7 | [delegated authentication](authentication.md#delegated-authentication), or [proxy user impersonation](authentication.md#proxy-user-impersonation). 8 | - `GetSessionToken`: Called by a user client to create a new [session](sessions.md). 9 | Requires [direct authentication](authentication.md#direct-authentication) or [proxy user impersonation](authentication.md#proxy-user-impersonation). 10 | - `RenewSessionToken`: Called by a [session](sessions.md) renewer to extend the lifetime of a session during the 11 | execution of a job. Requires [direct authentication](authentication.md#direct-authentication). 12 | - `CancelSessionToken`: Called by a [session](sessions.md) renewer to terminate a session at the end of a job. 13 | Requires [direct authentication](authentication.md#direct-authentication). 14 | 15 | ## Running the server 16 | 17 | To run the server: 18 | 19 | 1. Retrieve the JAR file for the broker server package from [Maven Central](https://search.maven.org/search?q=g:com.google.cloud.broker%20AND%20a:broker): 20 | ```xml 21 | com.google.cloud.broker 22 | broker-server 23 | ``` 24 | 2. Retrieve all the JAR files from Maven Central for the broker extensions (i.e. the [encryption backend](encryption.md#encryption-backends), 25 | [database backend](database.md#database-backends), [remote cache backends](caching.md#remote-cache-backends)) 26 | that you wish to use for your deployment. 27 | 3. Place all the JAR files in the `CLASSPATH`. 28 | 4. Create an `application.conf` file with the [settings](settings.md) for your environment. 29 | 5. [Initialize the database](database.md#database-initialization). 30 | 6. Run the following command: 31 | ```shell 32 | CONFIG_FILE=//application.conf java com.google.cloud.broker.apps.brokerserver.BrokerServer 33 | ``` 34 | -------------------------------------------------------------------------------- /docs/concepts/connector.md: -------------------------------------------------------------------------------- 1 | # Broker connector 2 | 3 | The broker connector is an extension for the [GCS Connector](https://github.com/GoogleCloudPlatform/bigdata-interop/tree/master/gcs), 4 | which acts as an interface between Hadoop and [Cloud Storage](https://cloud.google.com/storage/). 5 | 6 | The broker connector is used by the GCS Connector to access the broker service's gRPC endpoints. Recent minor versions 7 | of both Hadoop 2 & 3 are supported. 8 | 9 | You can find the broker connector's [package on Maven Central](https://search.maven.org/search?q=g:com.google.cloud.broker%20AND%20a:broker-connector): 10 | 11 | ```xml 12 | com.google.cloud.broker 13 | broker-connector 14 | ``` 15 | 16 | The broker connector can be downloaded as a single JAR file, which must be placed in the `CLASSPATH` of different 17 | environments: 18 | 19 | - On the user's client node, so the client can access the `GetAccessToken` and `GetSessionToken` endpoints. 20 | - On the master node(s) where the session token renewer (e.g. Yarn) is running, so the renewer can 21 | call the `RenewSessionToken` and `CancelSessionToken` endpoints. 22 | - On the worker nodes, so the distributed tasks can call the `GetAccessToken` to trade a session token for 23 | an access token. 24 | 25 | For more information, see the documentation about [authentication](authentication.md) and [sessions](sessions.md). 26 | 27 | ## Configuration properties 28 | 29 | This section contains all the available Hadoop configuration properties for the broker connector. 30 | 31 | ### `gcp.token.broker.kerberos.principal` 32 | 33 | Full name for the broker's Kerberos service principal. 34 | 35 | ### `gcp.token.broker.uri` 36 | 37 | URI for the broker server. If `https` is specified, then you must also provide either `gcp.token.broker.tls.certificate` 38 | or `gcp.token.broker.tls.certificate.path`. 39 | 40 | ### `gcp.token.broker.tls.certificate` 41 | 42 | Alternative to `gcp.token.broker.tls.certificate.path`. Contents of the TLS certificate for the broker service. 43 | Used only if `gcp.token.broker.tls.enabled` is `true`. 44 | 45 | ### `gcp.token.broker.tls.certificate.path` 46 | 47 | Alternative to `gcp.token.broker.tls.certificate`. File path of TLS certificate for the broker service. 48 | Used only if `gcp.token.broker.tls.enabled` is `true` and `gcp.token.broker.tls.certificate` is not provided. 49 | 50 | ## Configuration checks 51 | 52 | Run this command to verify that your client environment is correctly configured to connect to the server: 53 | 54 | ```shell 55 | java -cp $(hadoop classpath) com.google.cloud.broker.client.hadoop.fs.commands.PingServer 56 | ``` 57 | -------------------------------------------------------------------------------- /docs/concepts/encryption.md: -------------------------------------------------------------------------------- 1 | # Encryption 2 | 3 | The broker encrypts different types of information: 4 | 5 | - Access tokens before they are stored in the [remote cache](caching.md#remote-cache). 6 | - Refresh tokens used by the [refresh token provider](providers.md#refresh-token-provider), if that is the provider 7 | that you elect to use. 8 | 9 | ## Encryption backends 10 | 11 | To select a database backend, set the [`encryption.backend`](settings.md#encryptionbackend) setting 12 | to the backend's class path. 13 | 14 | Below is the list of available database backends: 15 | 16 | ### Cloud KMS 17 | 18 | _Class path:_ `com.google.cloud.broker.encryption.backends.CloudKMSBackend` 19 | 20 | The Cloud KMS backend uses [envelope encryption](https://cloud.google.com/kms/docs/envelope-encryption) 21 | to encrypt and decrypt data. It uses a [Cloud KMS](https://cloud.google.com/kms/) key encryption key (KEK) 22 | to wrap an AES256 data encryption key (DEK) stored in Cloud Storage or on the local filesystem. 23 | 24 | To generate the data encryption key and store it in Cloud Storage, run the 25 | `GenerateDEK` command: 26 | 27 | ```shell 28 | export BROKER_VERSION=$(cat VERSION) 29 | java -cp encryption-backend-cloud-kms-${BROKER_VERSION}-jar-with-dependencies.jar:code/core/target/broker-core-${BROKER_VERSION}-jar-with-dependencies.jar \ 30 | com.google.cloud.broker.encryption.GenerateDEK [dekUri] [kekUri] 31 | ``` 32 | 33 | * In the above command, replace `[dekUri]` with the URI of the DEK (e.g. `file:///path/to/dek.json` you want to store 34 | the DEK on the local system, or `gs://YOUR_BUCKET/dek.json` if you want to store the DEK on Cloud Storage). 35 | * Replace `[kekUri]` with the URI of the KEK: `projects/[PROJECT]/locations/[REGION]/keyRings/[KEY_RING]/cryptoKeys/[KEY_NAME]` 36 | (Replace the `[PROJECT]`, `[REGION]`, `[KEY_RING]`, and `[KEY_NAME]` with the appropriate values). 37 | * You can omit the `dekUri` and `kekUri` command parameters if you provide a [settings](settings.md) file with the 38 | [`encryption.cloud-kms.dek-uri`](settings.md#encryptioncloud-kmsdek-uri) and 39 | [`encryption.cloud-kms.kek-uri`](settings.md#encryptioncloud-kmskek-uri) settings. 40 | 41 | This backend is available as a [separate package on Maven Central](https://search.maven.org/search?q=g:com.google.cloud.broker%20AND%20a:encryption-backend-cloud-kms): 42 | 43 | ```xml 44 | com.google.cloud.broker 45 | encryption-backend-cloud-kms 46 | ``` 47 | 48 | This backend requires that you set the following setting(s): [`encryption.cloud-kms.kek-uri`](settings.md#encryptioncloud-kmskek-uri), 49 | [`encryption.cloud-kms.dek-uri`](settings.md#encryptioncloud-kmsdek-uri). 50 | 51 | ### Dummy encryption backend 52 | 53 | _Class path:_ `com.google.cloud.broker.encryption.backends.DummyEncryptionBackend` 54 | 55 | The Dummy encryption backend doesn't actually encrypt anything. It is only useful for testing 56 | and development purposes. Do _not_ use it in production. 57 | 58 | This backend is included in the [broker server](broker-server.md) package. 59 | -------------------------------------------------------------------------------- /docs/concepts/index.md: -------------------------------------------------------------------------------- 1 | # Concepts 2 | 3 | The conceptual documentation is divided in the following topics (here listed in alphabetical order): 4 | 5 | - [Access token providers](providers.md): All the different ways that the broker can generate access tokens. 6 | - [Authentication](authentication.md): All the different methods that clients can use to authenticate with the broker service. 7 | - [Authorizer](authorizer.md): How to use the Authorizer app. 8 | - [Broker connector](connector.md): How to use the broker connector, the client library to access the broker service from Hadoop. 9 | - [Broker server](broker-server.md): How to run the broker server app. 10 | - [Caching](caching.md): How the broker caches information for performance. 11 | - [Database](database.md): How the broker stores state. 12 | - [Encryption](encryption.md): How the broker encrypts sensitive information. 13 | - [Logging](logging.md): How to enable and view audit logs. 14 | - [Sessions](sessions.md): All you need to know about broker sessions. 15 | - [Settings](settings.md): List of all available settings. 16 | - [TLS](tls.md): Securing transport between broker clients and the broker service with TLS. 17 | - [User mapping](user-mapping.md): Mapping third-party user names to Google identity names. 18 | -------------------------------------------------------------------------------- /docs/concepts/logging.md: -------------------------------------------------------------------------------- 1 | # Logging 2 | 3 | ## Enabling GCS audit logs 4 | 5 | Follow these steps to enable GCS audit logs: 6 | 7 | 1. Go to: 8 | 9 | 2. In the "Filter table" text box, type "Google Cloud Storage" then press the "Enter" key. 10 | 11 | 3. Click on the "Google Cloud Storage" entry. 12 | 13 | 4. Tick the 3 checkboxes: "Admin Read", "Data Read", "Data Write". 14 | 15 | 5. Click "Save". 16 | 17 | ## Viewing GCS audit logs 18 | 19 | Follow these steps to view the GCS audit logs in Stackdriver: 20 | 21 | 1. Open the logs viewer in Stackdriver: 22 | 23 | 2. Click the down arrow in the text search box, then click "Convert to advanced filter". 24 | 25 | 3. Type the following in the text search box (Replace the **two** **`[PROJECT-ID]`** instances 26 | with your project ID and **`[BUCKET-NAME]`** with the name of your bucket): 27 | 28 | ```conf 29 | resource.type="gcs_bucket" 30 | resource.labels.bucket_name="[BUCKET-NAME]" 31 | logName="projects/[PROJECT-ID]/logs/cloudaudit.googleapis.com%2Fdata_access" 32 | ``` 33 | 34 | 4. Click "Submit Filter". 35 | -------------------------------------------------------------------------------- /docs/concepts/tls.md: -------------------------------------------------------------------------------- 1 | # TLS 2 | 3 | Communication between the [broker connector](connector.md) and the [broker server](broker-server.md) can be 4 | encrypted with [TLS](https://en.wikipedia.org/wiki/Transport_Layer_Security). 5 | 6 | TLS encryption is **highly recommended** for production environments. 7 | 8 | To enable TLS: 9 | 10 | 1. Create a domain for the broker service. 11 | 2. Get a certificate and private key from a [certificate authority](https://en.wikipedia.org/wiki/Certificate_authority). 12 | 3. Set the [`server.tls.enabled`](settings.md#servertlsenabled) setting to `true` and provide the certificate and 13 | private key with the [`server.tls.certificate-path`](settings.md#servertlscertificate-path) and 14 | [`server.tls.private-key-path`](settings.md#servertlsprivate-key-path) setting. 15 | 4. Configure the broker connector's [properties](connector.md#configuration-properties) to use TLS. 16 | -------------------------------------------------------------------------------- /docs/contribute/development.md: -------------------------------------------------------------------------------- 1 | ## Development 2 | 3 | ### Creating a development container 4 | 5 | You can use docker to create a container dedicated for development tasks. 6 | 7 | Create the container by running this command **from the repository's root**: 8 | 9 | ```shell 10 | ./run.sh init_dev 11 | ``` 12 | 13 | This installs all the dependencies needed to build packages and run the tests. 14 | 15 | ### Building packages 16 | 17 | To build all packages: 18 | 19 | ```shell 20 | ./run.sh build 21 | ``` 22 | 23 | To build an extension, for example the Redis caching backend: 24 | 25 | ```shell 26 | ./run.sh build -m redis 27 | ``` 28 | 29 | To build the broker connector: 30 | 31 | ```shell 32 | ./run.sh build -m connector 33 | ``` 34 | 35 | ### Building containers 36 | 37 | ```shell 38 | # Broker service 39 | docker build -f ./code/broker-server/Dockerfile -t gcr.io/${PROJECT}/broker-server . 40 | docker push gcr.io/$PROJECT/broker-server 41 | 42 | # Authorizer 43 | docker build -f ./code/authorizer/Dockerfile -t gcr.io/${PROJECT}/authorizer . 44 | docker push gcr.io/$PROJECT/authorizer 45 | ``` 46 | -------------------------------------------------------------------------------- /docs/contribute/index.md: -------------------------------------------------------------------------------- 1 | # How to Contribute 2 | 3 | We'd love to accept your patches and contributions to this project. There are 4 | just a few small guidelines you need to follow. 5 | 6 | ## Getting started 7 | 8 | Check out the following links to get started if you're interested in making code contributions 9 | to this project: 10 | 11 | - Set up a [development](development.md) environment 12 | - Run the [regression tests](regression-tests.md) 13 | - Run the [load tests](load-tests.md) 14 | 15 | Every contribution for bug fixes and new features should include unit tests and documentation to 16 | benefit other developers and facilitate the long-term maintenance of this project. 17 | 18 | Whenever possible, keep each pull request focused on a specific code change. Avoid mixing multiple 19 | bug fixes or new features in the same pull request. This will make it easier for the project 20 | maintainers to review your individual pull requests. This will also allow merging the reviewed 21 | PRs faster and not block them if other code changes need extra review time. 22 | 23 | Also, it is preferable to create pull requests based on the official master branch. 24 | 25 | ## Contributor License Agreement 26 | 27 | Contributions to this project must be accompanied by a Contributor License 28 | Agreement. You (or your employer) retain the copyright to your contribution; 29 | this simply gives us permission to use and redistribute your contributions as 30 | part of the project. Head over to to see 31 | your current agreements on file or to sign a new one. 32 | 33 | You generally only need to submit a CLA once, so if you've already submitted one 34 | (even if it was for a different project), you probably don't need to do it 35 | again. 36 | 37 | ## Code reviews 38 | 39 | All submissions, including submissions by project members, require review. We 40 | use GitHub pull requests for this purpose. Consult 41 | [GitHub Help](https://help.github.com/articles/about-pull-requests/) for more 42 | information on using pull requests. 43 | 44 | ## Community Guidelines 45 | 46 | This project follows 47 | [Google's Open Source Community Guidelines](https://opensource.google.com/conduct/). 48 | -------------------------------------------------------------------------------- /docs/contribute/load-tests.md: -------------------------------------------------------------------------------- 1 | ## Load testing 2 | 3 | This repository contains some load tests that use the [Locust](https://locust.io/) framework. 4 | 5 | You can run the load tests from the sample Dataproc cluster that you created for the demo. 6 | 7 | 1. SSH into the Dataproc master instance: 8 | 9 | ```shell 10 | gcloud compute ssh test-cluster-m 11 | ``` 12 | 13 | 2. Clone the project's repository: 14 | 15 | ```shell 16 | git clone https://github.com/GoogleCloudPlatform/gcp-token-broker 17 | cd gcp-token-broker/load-testing 18 | ``` 19 | 20 | 3. Install some dependencies: 21 | 22 | ```shell 23 | ./install.sh 24 | ``` 25 | 26 | 4. Create the Python gRPC stubs: 27 | 28 | ``shell 29 | python3 -m grpc_tools.protoc --proto_path=. --python_out=. --grpc_python_out=. brokerservice/protobuf/broker.proto 30 | ``` 31 | 32 | 5. Create a `settings.py` file using the provided template. 33 | 34 | ```shell 35 | cp settings.py.template settings.py 36 | ``` 37 | 38 | 6. Edit the `settings.py` to set appropriate values for your setup. 39 | 40 | 7. To run the load tests in headless mode: 41 | 42 | ```shell 43 | ~/.local/bin/locust --no-web -c 1000 -r 10 44 | ``` 45 | The `-c` corresponds to the total number of users, and `-r` the hatch rate 46 | (i.e. the number of new users spawned each passing second). To stop the tests, 47 | press `ctrl-c`. 48 | 49 | 8. To run the tests using the Web UI, start the Locust server: 50 | 51 | ```shell 52 | ~/.local/bin/locust 53 | ``` 54 | Then, in another terminal on your local machine, run the following command to set up 55 | a tunnel with the Dataproc master instance: 56 | 57 | ```shell 58 | gcloud compute start-iap-tunnel test-cluster-m 8089 \ 59 | --local-host-port=localhost:8089 60 | --zone $ZONE 61 | ``` 62 | Then open your browser at the address `http://localhost:8089` 63 | 64 | Note: During the execution of load tests, you might see some errors: `Too many open files`. 65 | This is because all users must read the Kerberos credentials from a temporary cache file, 66 | and the limit of open files allowed by the OS might be reached. To increase the limit, run 67 | the following command: 68 | 69 | ```shell 70 | ulimit -n 32768 71 | ``` 72 | -------------------------------------------------------------------------------- /docs/img/delegated-auth-sequence.txt: -------------------------------------------------------------------------------- 1 | participant alice\n@YOUR.REALM.COM as Alice 2 | participant Hadoop\nClient as Client 3 | participant GCS Connector\n(in Hadoop Client) as GCSConnClient 4 | participant On prem\nKDC as OnPremKDC 5 | participant Broker as Broker 6 | participant Yarn\nresource\nmanager as Yarn 7 | participant Client\nKDC as ClientKDC 8 | participant Yarn task as Task 9 | participant GCS Connector\n(in Task) as GCSConnTask 10 | participant GCS 11 | 12 | Alice -> Client: Submit job 13 | Client -> GCSConnClient: Read objects 14 | GCSConnClient -> OnPremKDC: Get SPNEGO token 15 | OnPremKDC -> GCSConnClient: Return SPNEGO token 16 | GCSConnClient -> Broker: Get session token\n(SPNEGO token) [fillcolor="white"] 17 | Broker -> Broker: Authenticate\nalice@YOUR.REALM.COM\nwith Kerberos/SPNEGO 18 | Broker -> Broker: Generate new\nsession token 19 | Broker -> Broker: Store session\ntoken details in\nbroker database 20 | Broker -> GCSConnClient: Return session token[fillcolor="white"] 21 | GCSConnClient -> Client: Return\nsession\ntoken 22 | Client -> Client: Store\nsession\ntoken in\njob context\nand UGI 23 | Client -> Yarn: Submit job [fillcolor="white"] 24 | Yarn -> ClientKDC: Get SPNEGO token 25 | ClientKDC -> Yarn: Return SPNEGO token 26 | Yarn -> Broker: Renew session token\n(SPNEGO token) 27 | Broker -> Broker: Authenticate Yarn\nwith Kerberos/SPNEGO 28 | Broker -> Broker: Verify Yarn is\nauthorized renewer 29 | Broker -> Broker: Extend session\ntoken's lifetime 30 | Yarn -> Task: Submit job[fillcolor="white"] 31 | Task -> GCSConnTask: Read\nobjects 32 | GCSConnTask -> GCSConnTask: Retrieve\nsession\ntoken from\nthe UGI[fillcolor="white"] 33 | GCSConnTask -> Broker: Get access token (session token)[fillcolor="white"] 34 | Broker -> Broker: Generate new\naccess token for\nalice@your-domain.com 35 | Broker -> GCSConnTask: Return access token[fillcolor="white"] 36 | GCSConnTask -> GCS: Read\nobjects 37 | GCS -> GCS: Verify\naccess\ncontrol\nfor alice\n@your-domain.com 38 | GCS -> GCSConnTask: Return\nobjects 39 | GCSConnTask -> Task: Return\nobjects 40 | Task -> Task: Process\nobjects 41 | Note over Task: Job runs until\ncompletion...[fillcolor="white"] 42 | Yarn -> Client: Return job result [fillcolor="white"] 43 | Yarn -> ClientKDC: Get SPNEGO token 44 | ClientKDC -> Yarn: Return SPNEGO token 45 | Yarn -> Broker: Cancel\nsession token\n(SPNEGO token) 46 | Broker -> Broker: Authenticate Yarn\nwith Kerberos/SPNEGO 47 | Broker -> Broker: Verify Yarn is\nauthorized renewer 48 | Broker -> Broker: Delete\nsession token\nfrom database -------------------------------------------------------------------------------- /docs/img/direct-auth-sequence.txt: -------------------------------------------------------------------------------- 1 | participant alice\n@YOUR.REALM.COM as Alice 2 | participant Hadoop Client as Client 3 | participant GCS Connector as GCSConn 4 | participant On prem\nKDC as OnPremKDC 5 | participant Broker as Broker 6 | participant GCS 7 | 8 | Alice -> Client: Submit job 9 | Client -> GCSConn: Read objects 10 | GCSConn -> OnPremKDC: Get SPNEGO token 11 | OnPremKDC -> GCSConn: Return SPNEGO token 12 | GCSConn -> Broker: Get access token\n(SPNEGO token) [fillcolor="white"] 13 | Broker -> Broker: Authenticate\nalice@YOUR.REALM.COM\nwith Kerberos/SPNEGO 14 | Broker -> Broker: Generate new\naccess token for\nalice@your-domain.com 15 | Broker -> GCSConn: Return access token [fillcolor="white"] 16 | GCSConn -> GCS: Read objects (access token)[fillcolor="white"] 17 | GCS -> GCS: Verify access\ncontrol for\nalice@your-domain.com 18 | GCS -> GCSConn: Return objects [fillcolor="white"] 19 | GCSConn -> Client: Return objects -------------------------------------------------------------------------------- /docs/img/dwd-admin-screen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleCloudPlatform/gcp-token-broker/2f70368c138d263b022a892f5442cc4b92b2d5fa/docs/img/dwd-admin-screen.png -------------------------------------------------------------------------------- /docs/img/dwd-service-accounts-screen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GoogleCloudPlatform/gcp-token-broker/2f70368c138d263b022a892f5442cc4b92b2d5fa/docs/img/dwd-service-accounts-screen.png -------------------------------------------------------------------------------- /docs/index.md: -------------------------------------------------------------------------------- 1 | ## Documentation 2 | 3 | The documentation is organized in different sections: 4 | 5 | - [Conceptual guides](concepts/index.md) discuss key concepts at a high-level and provide explanation 6 | about the design and rationale for the broker's components and behavior. 7 | - [Deployment guides](deploy/index.md) take you through a series of steps to deploy the broker service on GCP. 8 | - [Tutorials](tutorials/index.md) show some examples for testing the broker's functionality. 9 | - The [contributing guide](contribute/index.md) provides tips to get you started if you'd like to contribute code 10 | to this project. 11 | -------------------------------------------------------------------------------- /kubernetes/broker-server/templates/session-cleanup.yaml: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Google LLC 2 | # Licensed under the Apache License, Version 2.0 (the "License"); 3 | # you may not use this file except in compliance with the License. 4 | # You may obtain a copy of the License at 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # Unless required by applicable law or agreed to in writing, software 7 | # distributed under the License is distributed on an "AS IS" BASIS, 8 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | # See the License for the specific language governing permissions and 10 | # limitations under the License. 11 | 12 | apiVersion: batch/v1beta1 13 | kind: CronJob 14 | metadata: 15 | name: {{ .Chart.Name }}-session-cleanup 16 | labels: 17 | app: {{ .Chart.Name }} 18 | chart: '{{ .Chart.Name }}-{{ .Chart.Version }}' 19 | release: '{{ .Release.Name }}' 20 | heritage: '{{ .Release.Service }}' 21 | spec: 22 | schedule: '{{ .Values.sessionCleanup.schedule }}' 23 | jobTemplate: 24 | spec: 25 | template: 26 | spec: 27 | containers: 28 | - name: {{ .Chart.Name }}-session-cleanup-container 29 | image: {{ .Values.broker.image }} 30 | env: 31 | - name: CONFIG_FILE 32 | value: "/config/application.conf" 33 | command: 34 | - java 35 | - -cp 36 | - /classpath/* 37 | - com.google.cloud.broker.apps.brokerserver.sessions.SessionCleanup 38 | volumeMounts: 39 | - name: {{ .Chart.Name }}-config-volume 40 | mountPath: '/config' 41 | restartPolicy: OnFailure 42 | volumes: 43 | - name: {{ .Chart.Name }}-config-volume 44 | configMap: 45 | name: {{ .Chart.Name }}-settings-configmap -------------------------------------------------------------------------------- /load-testing/brokerservice/protobuf/broker.proto: -------------------------------------------------------------------------------- 1 | ../../../code/broker-server/src/main/proto/broker.proto -------------------------------------------------------------------------------- /load-testing/install.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Copyright 2020 Google LLC 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # Unless required by applicable law or agreed to in writing, software 9 | # distributed under the License is distributed on an "AS IS" BASIS, 10 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | # See the License for the specific language governing permissions and 12 | # limitations under the License. 13 | 14 | sudo apt-get install -y python3 15 | sudo apt-get install -y libkrb5-dev 16 | python3 -m pip install --user locustio==0.11.0 grpcio==1.19.0 grpcio-tools==1.19.0 gssapi==1.5.1 protobuf==3.6.1 -------------------------------------------------------------------------------- /load-testing/locustfile.py: -------------------------------------------------------------------------------- 1 | # Copyright Google Inc. 2019 2 | # Licensed under the Apache License, Version 2.0 (the "License"); 3 | # you may not use this file except in compliance with the License. 4 | # You may obtain a copy of the License at 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # Unless required by applicable law or agreed to in writing, software 7 | # distributed under the License is distributed on an "AS IS" BASIS, 8 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | # See the License for the specific language governing permissions and 10 | # limitations under the License. 11 | 12 | import subprocess 13 | 14 | from locust import Locust, TaskSequence, task, seq_task 15 | 16 | from client import BrokerClient 17 | from settings import TEST_USERS, REALM 18 | 19 | SCOPE = 'https://www.googleapis.com/auth/devstorage.read_write' 20 | BROKER_HOST = '10.2.1.255.nip.io' 21 | USER = TEST_USERS[0] 22 | USER_FULL = '{}@{}'.format(USER, REALM) 23 | 24 | 25 | def get_certificate(): 26 | # Retrieve the TLS certificate from the VM metadata 27 | out = subprocess.Popen( 28 | ['/usr/share/google/get_metadata_value', 'attributes/gcp-token-broker-tls-certificate'], 29 | stdout=subprocess.PIPE, 30 | stderr=subprocess.STDOUT) 31 | certificate, _ = out.communicate() 32 | return certificate 33 | 34 | 35 | class JobSimulation(TaskSequence): 36 | 37 | def on_start(self): 38 | self.client.kinit(USER_FULL, USER) 39 | 40 | def on_stop(self): 41 | self.client.kdestroy() 42 | 43 | @seq_task(1) 44 | def get_session_token(self): 45 | response = self.client.call_endpoint( 46 | 'GetSessionToken', 47 | parameters=dict(owner=USER_FULL, scopes=[SCOPE], renewer=USER_FULL) 48 | ) 49 | self.session_token = response.session_token 50 | 51 | @seq_task(2) 52 | def renew_session_token(self): 53 | self.client.call_endpoint( 54 | 'RenewSessionToken', 55 | parameters=dict(session_token=self.session_token), 56 | ) 57 | 58 | @seq_task(3) 59 | @task(100) 60 | def get_access_token(self): 61 | self.client.call_endpoint( 62 | 'GetAccessToken', 63 | session_token=self.session_token 64 | ) 65 | 66 | @seq_task(4) 67 | def cancel_session_token(self): 68 | self.client.call_endpoint( 69 | 'CancelSessionToken', 70 | parameters=dict(session_token=self.session_token), 71 | ) 72 | 73 | 74 | class BrokerUser(Locust): 75 | host = BROKER_HOST 76 | task_set = JobSimulation 77 | min_wait = 0 78 | max_wait = 1 79 | 80 | def __init__(self, *args, **kwargs): 81 | self.client = BrokerClient(self.host, get_certificate()) 82 | -------------------------------------------------------------------------------- /load-testing/settings.py.template: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Google LLC 2 | # Licensed under the Apache License, Version 2.0 (the "License"); 3 | # you may not use this file except in compliance with the License. 4 | # You may obtain a copy of the License at 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # Unless required by applicable law or agreed to in writing, software 7 | # distributed under the License is distributed on an "AS IS" BASIS, 8 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | # See the License for the specific language governing permissions and 10 | # limitations under the License. 11 | 12 | REALM = '' 13 | TEST_USERS = ['alice', 'bob', 'john'] -------------------------------------------------------------------------------- /terraform/peering.tf: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Google LLC 2 | # Licensed under the Apache License, Version 2.0 (the "License"); 3 | # you may not use this file except in compliance with the License. 4 | # You may obtain a copy of the License at 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # Unless required by applicable law or agreed to in writing, software 7 | # distributed under the License is distributed on an "AS IS" BASIS, 8 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | # See the License for the specific language governing permissions and 10 | # limitations under the License. 11 | 12 | 13 | // Client <--> Origin --------------------------------------------------------------- 14 | 15 | resource "google_compute_network_peering" "client_origin_peering1" { 16 | name = "client-origin-peering1" 17 | network = google_compute_network.client.self_link 18 | peer_network = google_compute_network.origin.self_link 19 | depends_on = [ 20 | google_compute_subnetwork.origin_subnet, 21 | google_compute_subnetwork.client_subnet, 22 | ] 23 | } 24 | 25 | resource "google_compute_network_peering" "client_origin_peering2" { 26 | name = "client-origin-peering2" 27 | network = google_compute_network.origin.self_link 28 | peer_network = google_compute_network.client.self_link 29 | } 30 | -------------------------------------------------------------------------------- /terraform/shadow.tf: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Google LLC 2 | # Licensed under the Apache License, Version 2.0 (the "License"); 3 | # you may not use this file except in compliance with the License. 4 | # You may obtain a copy of the License at 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # Unless required by applicable law or agreed to in writing, software 7 | # distributed under the License is distributed on an "AS IS" BASIS, 8 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | # See the License for the specific language governing permissions and 10 | # limitations under the License. 11 | 12 | resource "google_service_account" "test_user_serviceaccount" { 13 | count = length(var.test_users) 14 | account_id = "${element(var.test_users, count.index)}-shadow" 15 | display_name = "${element(var.test_users, count.index)}'s shadow service account" 16 | } 17 | 18 | resource "google_service_account_iam_member" "token_creator_0" { 19 | service_account_id = google_service_account.test_user_serviceaccount[0].name 20 | role = "roles/iam.serviceAccountTokenCreator" 21 | member = "serviceAccount:${google_service_account.broker.email}" 22 | } 23 | 24 | resource "google_service_account_iam_member" "token_creator_1" { 25 | service_account_id = google_service_account.test_user_serviceaccount[1].name 26 | role = "roles/iam.serviceAccountTokenCreator" 27 | member = "serviceAccount:${google_service_account.broker.email}" 28 | } 29 | 30 | -------------------------------------------------------------------------------- /terraform/startup-script-kdc.tpl: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Google LLC 2 | # Licensed under the Apache License, Version 2.0 (the "License"); 3 | # you may not use this file except in compliance with the License. 4 | # You may obtain a copy of the License at 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # Unless required by applicable law or agreed to in writing, software 7 | # distributed under the License is distributed on an "AS IS" BASIS, 8 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | # See the License for the specific language governing permissions and 10 | # limitations under the License. 11 | 12 | # In general we want to enable debug through -x 13 | # But there are also some commands involving passwords/keys 14 | # so make sure you turn it off (set +x) before such commands. 15 | set -xeuo pipefail 16 | 17 | apt-get update 18 | 19 | DEBIAN_FRONTEND=noninteractive apt-get -yq install krb5-kdc krb5-admin-server 20 | 21 | cat << EOF > /etc/krb5.conf 22 | [realms] 23 | ${realm} = { 24 | kdc = localhost:88 25 | admin_server = localhost:749 26 | } 27 | [libdefaults] 28 | default_realm = ${realm} 29 | dns_lookup_realm = false 30 | dns_lookup_kdc = false 31 | EOF 32 | 33 | 34 | cat << EOF > /etc/krb5kdc/kdc.conf 35 | [kdcdefaults] 36 | kdc_ports = 750,88 37 | 38 | [realms] 39 | ${realm} = { 40 | database_name = /var/lib/krb5kdc/principal 41 | admin_keytab = FILE:/etc/krb5kdc/kadm5.keytab 42 | acl_file = /etc/krb5kdc/kadm5.acl 43 | key_stash_file = /etc/krb5kdc/stash 44 | kdc_ports = 750,88 45 | max_life = 10h 0m 0s 46 | max_renewable_life = 7d 0h 0m 0s 47 | master_key_type = aes256-cts 48 | supported_enctypes = aes256-cts:normal arcfour-hmac:normal des3-hmac-sha1:normal des-cbc-crc:normal des:normal des:v4 des:norealm des:onlyrealm des:afs3 49 | default_principal_flags = +preauth 50 | } 51 | EOF 52 | 53 | 54 | cat << EOF >> /etc/krb5kdc/kadm5.acl 55 | root * 56 | EOF 57 | 58 | mkdir /var/log/kerberos 59 | touch /var/log/kerberos/krb5libs.log 60 | touch /var/log/kerberos/krb5kdc.log 61 | touch /var/log/kerberos/kadmind.log 62 | 63 | KDC_DB_KEY=$(openssl rand -base64 32) 64 | /usr/sbin/kdb5_util create -s -W -P "$${KDC_DB_KEY}" 65 | 66 | systemctl enable krb5-kdc; systemctl restart krb5-kdc 67 | systemctl enable krb5-admin-server; systemctl restart krb5-admin-server 68 | 69 | kadmin.local -q "addprinc -randkey root" 70 | 71 | ${extra_commands} 72 | 73 | echo " 74 | export REALM=${realm} 75 | export PROJECT=$(curl -s "http://metadata.google.internal/computeMetadata/v1/project/project-id" -H "Metadata-Flavor: Google") 76 | export ZONE=$(curl -s "http://metadata.google.internal/computeMetadata/v1/instance/zone" -H "Metadata-Flavor: Google" | awk -F/ '{print $NF}') 77 | " > /etc/profile.d/extra_env_vars.sh -------------------------------------------------------------------------------- /terraform/variables.tf: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Google LLC 2 | # Licensed under the Apache License, Version 2.0 (the "License"); 3 | # you may not use this file except in compliance with the License. 4 | # You may obtain a copy of the License at 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # Unless required by applicable law or agreed to in writing, software 7 | # distributed under the License is distributed on an "AS IS" BASIS, 8 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | # See the License for the specific language governing permissions and 10 | # limitations under the License. 11 | 12 | variable "gcp_project" { 13 | } 14 | 15 | variable "gcp_region" { 16 | default = "us-west1" 17 | } 18 | 19 | variable "gcp_zone" { 20 | default = "us-west1-a" 21 | } 22 | 23 | variable "datastore_region" { 24 | default = "us-west2" 25 | } 26 | 27 | variable "origin_realm" { 28 | } 29 | 30 | variable "gsuite_domain" { 31 | } 32 | 33 | // Origin KDC -------------------------------------- 34 | 35 | variable "origin_subnet_cidr" { 36 | default = "10.11.0.0/29" 37 | } 38 | 39 | variable "origin_kdc_ip" { 40 | default = "10.11.0.3" 41 | } 42 | 43 | // Client ---------------------------------------- 44 | 45 | variable "client_subnet_cidr" { 46 | default = "10.21.0.0/16" 47 | } 48 | 49 | variable "dataproc_root_password" { 50 | default = "change-me" 51 | } 52 | 53 | // Cross-realm trust ----------------------------- 54 | 55 | variable "cross_realm_password" { 56 | default = "change-me" 57 | } 58 | 59 | variable dataproc_realm { 60 | default = "DATAPROC_REALM" 61 | } 62 | 63 | // Test users ------------------------------------ 64 | 65 | variable "test_users" { 66 | type = list(string) 67 | default = ["alice", "bob", "charlie"] 68 | } 69 | 70 | -------------------------------------------------------------------------------- /terraform/versions.tf: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Google LLC 2 | # Licensed under the Apache License, Version 2.0 (the "License"); 3 | # you may not use this file except in compliance with the License. 4 | # You may obtain a copy of the License at 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # Unless required by applicable law or agreed to in writing, software 7 | # distributed under the License is distributed on an "AS IS" BASIS, 8 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | # See the License for the specific language governing permissions and 10 | # limitations under the License. 11 | 12 | terraform { 13 | required_version = ">= 0.12" 14 | } 15 | 16 | terraform { 17 | required_providers { 18 | google = { 19 | source = "hashicorp/google" 20 | version = "4.31.0" 21 | } 22 | null = { 23 | source = "hashicorp/null" 24 | version = "3.1.1" 25 | } 26 | template = { 27 | source = "hashicorp/template" 28 | version = "2.2.0" 29 | } 30 | local = { 31 | source = "hashicorp/local" 32 | version = "2.2.3" 33 | } 34 | } 35 | } 36 | 37 | provider "google" { 38 | project = var.gcp_project 39 | region = var.gcp_region 40 | zone = var.gcp_zone 41 | } --------------------------------------------------------------------------------