Basic Overview of a Connector Framework - Functional

IDHub Connectors Framework Overview shows the different modules that make up the Connector Framework.

Requirements for Target System

  • Be clear with the requirements of the Splice. Basic naming conventions and other requirements will be mentioned here. IDHUB-2613

  • Know the different Resources that are applicable to the Target System. Resources of IDHub are of two types - Accounts and Entitlements.

  • Different Target Systems may have different Entitlement Resources. For example, Confluence has two types of Entitlements - Groups and Spaces.

  • Familiarise with the Target System to see the way Accounts and Entitlements are displayed/added/updated/deleted.

Analysis and Design for Target System

A design document shows how the Accounts and Entitlements of a Target System are mapped to the Accounts and Entitlements of IDHub, functionalities of Splice that are developed and also the pseudo code for Splice development.

  • Search for Target System documentations that provide APIs that enable users to fetch/create/modify/delete Accounts and Entitlements in the Target System.

  • Call the APIs from Postman to verify functionality in the Target System. An account in the Target System may be required for this.

  • Identify the fields of each Resource of the Target System - mandatory and optional (as per IDHub requirements) .

  • Decide the Schema of the Target System Resources - If the Target System does not provide an API representing the Resource Schema, then the Schema needs to be built manually based on Resource fields.

  • Create the design document with all the necessary information and pseudo code.

Confluence Splice is the design document for Confluence which contains all necessary information to develop the Splice.

Splice development

Basic Requirements

  • The Splice needs to implement idhub-connector-spi and idhub-connector-application.

  • A sample build.gradle file is attached

build.gradle
plugins {
    id 'maven-publish'
    id 'idea'
    id 'java'
    id 'org.sonarqube' version '3.3'
    id 'com.palantir.docker' version '0.31.0'
    id 'com.palantir.docker-run' version '0.31.0'
    id 'com.palantir.git-version' version '0.12.3'
    id 'org.springframework.boot' version '2.6.1'
    id 'io.spring.dependency-management' version '1.0.11.RELEASE'
}

apply plugin: 'io.spring.dependency-management'
apply plugin: 'com.palantir.docker'
apply plugin: 'idea'

project.description = 'Confluence Splice'
project.version = '22.0.0'
project.group = 'com.sath.idhub'

String CONNECTOR_VERSION = '2.1.6'
String CONNECTOR_SPI_VERSION = '3.2.1'

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-actuator'
    implementation 'org.springframework.boot:spring-boot-starter-oauth2-client'
    implementation 'org.springframework.boot:spring-boot-starter-oauth2-resource-server'
    implementation 'org.springframework.boot:spring-boot-starter-security'
    implementation 'org.springframework.boot:spring-boot-starter-web'
    implementation 'org.springframework.boot:spring-boot-starter-webflux'
    implementation 'org.springframework.boot:spring-boot-configuration-processor'

    implementation 'com.google.code.findbugs:jsr305:3.0.2'

    implementation 'com.fasterxml.jackson.core:jackson-core:2.13.2'
    implementation 'com.fasterxml.jackson.core:jackson-annotations:2.13.2'
    implementation 'com.fasterxml.jackson.core:jackson-databind:2.13.2'
    implementation 'com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:2.13.1'

    implementation 'org.apache.commons:commons-lang3:3.12.0'

    implementation 'com.atlassian.confluence:confluence:7.12.2'
    implementation 'com.googlecode.json-simple:json-simple:1.1.1'

    implementation "com.sath.idhub:idhub-connector-spi:${CONNECTOR_SPI_VERSION}"
    implementation "com.sath.idhub:idhub-connector-application:${CONNECTOR_VERSION}"

    compileOnly 'org.projectlombok:lombok'

    testImplementation 'org.springframework.security:spring-security-test:5.6.2'
    testImplementation 'org.springframework.boot:spring-boot-starter-test:2.6.4'
    testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.2'
    testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.2'
}

// Intellij Idea Configurations for Javadocs and Sources
idea {
    module {
        downloadJavadoc = true
        downloadSources = true
    }
}

// Docker
String dockerAndMavenRepoUsername = System.env['IDHUB_DOCKER_USER']
String dockerAndMavenRepoPassword = System.env['IDHUB_DOCKER_PASSWORD']

// Settings to pull from maven central and sath repositories
repositories {
    mavenCentral()
    maven {
        url = uri('https://maven.atlassian.com/repository/public')
    }
    maven {
        url "https://repo.sath.com/repository/maven-snapshots/"
        credentials {
            username dockerAndMavenRepoUsername
            password dockerAndMavenRepoPassword
        }
    }
    maven {
        url "https://repo.sath.com/repository/maven-releases/"
        credentials {
            username dockerAndMavenRepoUsername
            password dockerAndMavenRepoPassword
        }
    }
}

java.sourceCompatibility = JavaVersion.VERSION_17

java {
    withSourcesJar()
    withJavadocJar()
}

jar {
    // Spring set this to plain so their springboot jar can be unclassified
    // Unclassified is going to be uploaded to maven repo
    archiveClassifier = ''
}

bootJar {
    // The rebuilt fat springboot jar get classified as with-connector
    // This is the jar that gets is used in the Dockerfile
    archiveClassifier = "with-connector-${CONNECTOR_VERSION}"
    manifest {
        attributes 'Main-Class': 'org.springframework.boot.loader.PropertiesLauncher'
    }
    mainClass = 'com.sath.idhub.connector.application.ConnectorApplication'
}

test {
    //enabled=false
    // This is for JUnit 5
    useJUnitPlatform()
}

// Link publish to building
tasks.publish.dependsOn(tasks.build)
publishing {
    repositories {
        maven {
            url version.endsWith('SNAPSHOT')
                    ? "https://repo.sath.com/repository/maven-snapshots/"
                    : "https://repo.sath.com/repository/maven-releases/"

            credentials {
                username dockerAndMavenRepoUsername
                password dockerAndMavenRepoPassword
            }
        }
    }


    publications {
        myPublication(MavenPublication) {
            from components.java

            pom {
                name = project.name
                description = project.description
                developers {
                    developer {
                        name = System.properties.get('user.name')
                    }
                }
            }
        }
    }
}

def gitVersion = versionDetails()

String dockerName = 'docker.sath.com/confluence-idhub-connector:' + gitVersion.branchName.split('/').last()

tasks.dockerPrepare.dependsOn(tasks.bootJar)
tasks.docker.dependsOn(tasks.build)
tasks.dockerPush.dependsOn(tasks.dockerTag)
tasks.dockerPrepare.dependsOn(tasks.jar)
tasks.dockerPrepare.dependsOn(tasks.javadocJar)
tasks.dockerPrepare.dependsOn(tasks.sourcesJar)

docker {
    name = dockerName

    copySpec.from('src/main/docker').into('.')
            .from('build/libs').into('.')

    tag 'Nexus', "$dockerName"

    buildArgs([
            SPLICE_VERSION: project.version,
            CONNECTOR_VERSION : CONNECTOR_VERSION
    ])

    labels([
            'build-time'         : new Date(),
            'user.name'          : System.properties.get('user.name'),
            'java.vm.version'    : System.properties.get('java.vm.version'),
            'java.runtime.name'  : System.properties.get('java.runtime.name'),
            'git-commit-hash'    : gitVersion.gitHash,
            'git-branch'         : gitVersion.branchName,
            'git-last-tag'       : gitVersion.lastTag,
            'git-commit-distance': gitVersion.commitDistance,
            'git-clean'          : gitVersion.isCleanTag,
    ])
}

dockerRun {
    name project.name
    image dockerName
    ports '8086:8086'
    daemonize true
    command 'sleep', '100'
    arguments '--hostname=custom', '-P'
}

tasks.register("getDockerImageName") {
    println dockerName
}

tasks.register("info") {
    System.out.println 'Building Project :' + project.name
    System.out.println 'Description :' + project.description
    System.out.println 'Last Tag :' + gitVersion.lastTag
    System.out.println 'Git Commit Distance : ' + gitVersion.commitDistance
    System.out.println 'Git Hash : ' + gitVersion.gitHash
    System.out.println 'Branch : ' + gitVersion.branchName
    System.out.println 'Git isClean : ' + gitVersion.isCleanTag
    System.out.println 'Docker Image Name : ' + dockerName
    System.out.println 'Current Timestamp : ' + new Date()
    System.out.println 'User : ' + System.properties.get('user.name')
}
CODE

Splice Development

Splice development consists of :

  • CommonConnectorService implementation

public class ConnectorService implements CommonConnectorService {}
CODE
  • ScimResourceService implementation for the different Target System Resources

public class AccountResourceService implements ScimResourceService {}
CODE
  • Resource models that contain the different fields to define Resource Schema

public class Account extends IdhubObject {}
CODE

Unit Testing

Unit Testing tests the proper functioning of all endpoints that will be used by IDHub

  • Create sample Resources to test GET, POST, PUT, PATCH, DELETE and Search functionalities.

Scenarios to cover

  • Functionality of the connector for Accounts :

    1. Create (with/without entitlements)

    2. Get account by ID

    3. Update - via patch add/remove Entitlements, replace attributes. (PATCH operation)

    4. Replace account with/without Entitlements via put (PUT operation)

    5. Delete

    6. List accounts

    7. Provide account schema

  • Functionality of the connector for Entitlements :

    1. Provide entitlement schema

    2. Get entitlement by ID

    3. List entitlements

    4. Create entitlement (Not mandatory for this version, may/may not be added)

    5. Replace entitlement via Put operation (Not mandatory for this version, may/may not be added)

    6. Delete (Not mandatory for this version, may/may not be added)

Deployment Document

This contains the steps necessary for a user to :

  • setup the Splice as a runnable JAR

  • setup the Admin Account in Target System that will interact with IDHub

End to End Testing and Integration Testing

  • Once deployed, the Splice can be tested using IDHub by provisioning and reconciling Accounts and Entitlements

  • The same steps can be made into Integration Tests.