Skip to content

Commit

Permalink
MVP: Okta SSO in Airbyte Pro (#7110)
Browse files Browse the repository at this point in the history
Co-authored-by: josephkmh <[email protected]>
Co-authored-by: Parker Mossman <[email protected]>
Co-authored-by: Flutra Osmani <[email protected]>
Co-authored-by: Joey Marshment-Howell <[email protected]>
Co-authored-by: Flutra Osmani <[email protected]>
Co-authored-by: Tim Roes <[email protected]>
Co-authored-by: Joey Marshment-Howell <[email protected]>
Co-authored-by: Jose Pefaur <[email protected]>
Co-authored-by: Jimmy Ma <[email protected]>
Co-authored-by: Octavia Squidington III <[email protected]>
Co-authored-by: maxi297 <[email protected]>
Co-authored-by: maxi297 <[email protected]>
Co-authored-by: Topher Lubaway <[email protected]>
Co-authored-by: Alex Birdsall <[email protected]>
Co-authored-by: Teal Larson <[email protected]>
Co-authored-by: Mike Saffitz <[email protected]>
Co-authored-by: Michael Saffitz <[email protected]>
Co-authored-by: Peter Hu <[email protected]>
Co-authored-by: terencecho <[email protected]>
Co-authored-by: terencecho <[email protected]>
Co-authored-by: Cole Snodgrass <[email protected]>
Co-authored-by: Vladimir <[email protected]>
Co-authored-by: Davin Chia <[email protected]>
Co-authored-by: Jon Tan <[email protected]>
Co-authored-by: Benoit Moriceau <[email protected]>
Co-authored-by: Lake Mossman <[email protected]>
Co-authored-by: Joe Reuter <[email protected]>
Co-authored-by: Chandler Prall <[email protected]>
Co-authored-by: Alexandre Girard <[email protected]>
Co-authored-by: octavia-approvington <[email protected]>
Co-authored-by: perangel <[email protected]>
Co-authored-by: Jose Pefaur <[email protected]>
Co-authored-by: Ryan Br <[email protected]>
Co-authored-by: flutra-osmani <[email protected]>
Co-authored-by: git-phu <[email protected]>
Co-authored-by: Pedro S. Lopez <[email protected]>
  • Loading branch information
1 parent 529c754 commit 787ab44
Show file tree
Hide file tree
Showing 104 changed files with 3,584 additions and 86 deletions.
6 changes: 6 additions & 0 deletions .bumpversion.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -43,3 +43,9 @@ replace = "version": "{new_version}"
[bumpversion:file:charts/airbyte/README.md]

[bumpversion:file:airbyte-connector-builder-server/Dockerfile]

[bumpversion:file:charts/airbyte-keycloak/Chart.yaml]

[bumpversion:file:charts/airbyte-keycloak-setup/Chart.yaml]

[bumpversion:file:airbyte-keycloak-setup/Dockerfile]
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -84,3 +84,7 @@ charts/**/charts

# Datadog
dd-java-agent.jar

# Ignore airbyte.yml since this file contains user-provided information that is sensitive and should not be committed
# See airbyte.sample.yml for an example of the expected file structure.
airbyte.yml
49 changes: 49 additions & 0 deletions airbyte-api/src/main/openapi/config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2941,6 +2941,22 @@ paths:
application/json:
schema:
$ref: "#/components/schemas/StreamStatusRead"
# Instance Configuration
/v1/instance_configuration:
get:
tags:
- instance_configuration
summary: Get instance configuration
operationId: getInstanceConfiguration
responses:
"200":
description: Successfully returned instance configuration.
content:
application/json:
schema:
$ref: "#/components/schemas/InstanceConfigurationResponse"
"401":
description: Fetching instance configuration failed.
/v1/jobs/retry_states/create_or_update:
post:
summary: Creates or updates a retry state for a job.
Expand Down Expand Up @@ -6508,6 +6524,39 @@ components:
properties:
id:
$ref: "#/components/schemas/StreamStatusId"
AuthConfiguration:
type: object
required:
- clientId
- defaultRealm
properties:
clientId:
type: string
default: "airbyte-webapp"
defaultRealm:
type: string
default: "airbyte"
InstanceConfigurationResponse:
type: object
required:
- edition
- webappUrl
properties:
edition:
type: string
enum:
- community
- pro
licenseType:
type: string
enum:
- pro
- invalid
nullable: true
auth:
$ref: "#/components/schemas/AuthConfiguration"
webappUrl:
type: string
StreamStatusRead:
type: object
required:
Expand Down
28 changes: 28 additions & 0 deletions airbyte-commons-auth/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
plugins {
id "io.airbyte.gradle.jvm.lib"
id "io.airbyte.gradle.publish"
}

dependencies {
annotationProcessor platform(libs.micronaut.bom)
annotationProcessor libs.bundles.micronaut.annotation.processor

implementation platform(libs.micronaut.bom)
implementation libs.bundles.micronaut
compileOnly libs.lombok
annotationProcessor libs.lombok

implementation project(':airbyte-commons')

testAnnotationProcessor platform(libs.micronaut.bom)
testAnnotationProcessor libs.bundles.micronaut.test.annotation.processor
testCompileOnly libs.lombok
testAnnotationProcessor libs.lombok

testImplementation libs.bundles.micronaut.test
testImplementation libs.mockito.inline
}

test {
maxHeapSize = '2g'
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/*
* Copyright (c) 2023 Airbyte, Inc., all rights reserved.
*/

package io.airbyte.commons.auth.config;

import io.micronaut.context.annotation.ConfigurationProperties;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import lombok.extern.slf4j.Slf4j;

/**
* This class bundles all internal Keycloak configuration into a convenient singleton that can be
* consumed by multiple Micronaut applications. Each application still needs to define each property
* in application.yml. TODO figure out how to avoid redundant configs in each consuming
* application.yml
*/
@ConfigurationProperties("airbyte.keycloak")
@Getter
@Setter
@Slf4j
@ToString
@SuppressWarnings({"MissingJavadocMethod"})
public class AirbyteKeycloakConfiguration {

String protocol;
String host;
String basePath;
String airbyteRealm;
String realm;
String clientId;
String redirectUri;
String webClientId;
String accountClientId;
String username;
String password;

public String getKeycloakUserInfoEndpoint() {
final String hostWithoutTrailingSlash = host.endsWith("/") ? host.substring(0, host.length() - 1) : host;
final String basePathWithLeadingSlash = basePath.startsWith("/") ? basePath : "/" + basePath;
final String keycloakUserInfoURI = "/protocol/openid-connect/userinfo";
return protocol + "://" + hostWithoutTrailingSlash + basePathWithLeadingSlash + "/realms/" + airbyteRealm + keycloakUserInfoURI;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/*
* Copyright (c) 2023 Airbyte, Inc., all rights reserved.
*/

package io.airbyte.commons.auth.config;

import io.micronaut.context.annotation.EachProperty;
import lombok.Getter;
import lombok.ToString;
import lombok.extern.slf4j.Slf4j;

/**
* This class pulls together all the auth identity provider configuration as defined in airbyte.yml.
* It can be injected as a single dependency, rather than injecting each individual value
* separately.
*/
@EachProperty(value = "airbyte.auth.identity-providers",
list = true)
@Getter
@Slf4j
@ToString
@SuppressWarnings({"MissingJavadocType"})
public class IdentityProviderConfiguration {

public enum ProviderType {
OKTA
}

ProviderType type;
String domain;
String appName;
String clientId;
String clientSecret;

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/*
* Copyright (c) 2023 Airbyte, Inc., all rights reserved.
*/

package io.airbyte.commons.auth.config;

import io.micronaut.context.annotation.ConfigurationProperties;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;

/**
* This class pulls together all the auth user configuration as defined in airbyte.yml. It can be
* injected as a single dependency, rather than injecting each individual value separately.
*/
@ConfigurationProperties("airbyte.initial-user")
@Getter
@Slf4j
public class InitialUserConfiguration {

String email;
String firstName;
String lastName;
String username;
String password;

}
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@
* Copyright (c) 2023 Airbyte, Inc., all rights reserved.
*/

package io.airbyte.commons.auth;
package io.airbyte.commons.auth.roles;

import static org.junit.jupiter.api.Assertions.assertEquals;

import io.airbyte.commons.auth.AuthRole;
import java.util.Set;
import org.junit.jupiter.api.Test;

Expand Down
29 changes: 29 additions & 0 deletions airbyte-commons-license/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
plugins {
id "io.airbyte.gradle.jvm.lib"
id "io.airbyte.gradle.publish"
}

dependencies {
annotationProcessor platform(libs.micronaut.bom)
annotationProcessor libs.bundles.micronaut.annotation.processor

implementation platform(libs.micronaut.bom)
implementation libs.bundles.micronaut
implementation libs.guava
compileOnly libs.lombok
annotationProcessor libs.lombok

implementation project(':airbyte-commons')

testAnnotationProcessor platform(libs.micronaut.bom)
testAnnotationProcessor libs.bundles.micronaut.test.annotation.processor
testCompileOnly libs.lombok
testAnnotationProcessor libs.lombok

testImplementation libs.bundles.micronaut.test
testImplementation libs.mockito.inline
}

test {
maxHeapSize = '2g'
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/*
* Copyright (c) 2023 Airbyte, Inc., all rights reserved.
*/

package io.airbyte.commons.license;

import io.airbyte.commons.license.AirbyteLicense.LicenseType;
import io.airbyte.commons.license.annotation.RequiresAirbyteProEnabled;
import jakarta.inject.Singleton;
import java.util.Optional;
import lombok.extern.slf4j.Slf4j;

/**
* Bean that contains the Airbyte License that is retrieved from the licensing server at application
* startup.
*/
@Slf4j
@Singleton
@RequiresAirbyteProEnabled
public class ActiveAirbyteLicense {

private Optional<AirbyteLicense> airbyteLicense;

public void setLicense(final AirbyteLicense airbyteLicense) {
this.airbyteLicense = Optional.ofNullable(airbyteLicense);
}

public Optional<AirbyteLicense> getLicense() {
return airbyteLicense;
}

/**
* Returns the type of the license. If no license is present, defaults to INVALID.
*/
public LicenseType getLicenseType() {
return airbyteLicense.map(AirbyteLicense::type).orElse(LicenseType.INVALID);
}

public boolean isPro() {
return airbyteLicense.map(license -> license.type().equals(LicenseType.PRO)).orElse(false);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/*
* Copyright (c) 2023 Airbyte, Inc., all rights reserved.
*/

package io.airbyte.commons.license;

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonValue;

/**
* An immutable representation of an Airbyte License.
*/
@SuppressWarnings({"MissingJavadocMethod", "MissingJavadocType"})
public record AirbyteLicense(LicenseType type) {

public enum LicenseType {

PRO("pro"),
INVALID("invalid");

private final String value;

LicenseType(String value) {
this.value = value;
}

@JsonValue
public String getValue() {
return value;
}

@Override
public String toString() {
return String.valueOf(value);
}

@JsonCreator
public static LicenseType fromValue(String value) {
for (LicenseType b : LicenseType.values()) {
if (b.value.equals(value)) {
return b;
}
}
throw new IllegalArgumentException("Unexpected value '" + value + "'");
}

}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/*
* Copyright (c) 2023 Airbyte, Inc., all rights reserved.
*/

package io.airbyte.commons.license;

import io.airbyte.commons.license.annotation.RequiresAirbyteProEnabled;
import io.micronaut.context.annotation.Context;
import lombok.extern.slf4j.Slf4j;

/**
* Service that establishes the active Airbyte License. This is annotated with @Context so that it
* occurs during application initialization, so that the license is available for downstream beans
* to conditionally activate.
*/
@Context
@Slf4j
@RequiresAirbyteProEnabled
public class AirbyteLicenseContextService {

public AirbyteLicenseContextService(final AirbyteLicenseFetcher airbyteLicenseFetcher, final ActiveAirbyteLicense activeAirbyteLicense) {
activeAirbyteLicense.setLicense(airbyteLicenseFetcher.fetchLicense());
}

}
Loading

0 comments on commit 787ab44

Please sign in to comment.