Skip to content

Commit

Permalink
Restore flank auth login
Browse files Browse the repository at this point in the history
  • Loading branch information
bootstraponline committed Feb 23, 2019
1 parent fcb2cec commit c582cce
Show file tree
Hide file tree
Showing 9 changed files with 149 additions and 80 deletions.
10 changes: 5 additions & 5 deletions test_runner/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -127,13 +127,13 @@ dependencies {
testImplementation("com.github.stefanbirkner:system-rules:1.19.0")

// https://github.com/ktorio/ktor/releases
val ktorVersion = "1.1.1"
testImplementation("io.ktor:ktor-server-core:$ktorVersion")
testImplementation("io.ktor:ktor-server-netty:$ktorVersion")
testImplementation("io.ktor:ktor-gson:$ktorVersion")
val ktorVersion = "1.1.3"
compile("io.ktor:ktor-server-core:$ktorVersion")
compile("io.ktor:ktor-server-netty:$ktorVersion")
compile("io.ktor:ktor-gson:$ktorVersion")

// https://github.com/qos-ch/logback/releases
testImplementation("ch.qos.logback:logback-classic:1.2.3")
compile("ch.qos.logback:logback-classic:1.2.3")
// mockito-inline is used to mock final classes
// https://github.com/mockito/mockito/releases
testImplementation("org.mockito:mockito-inline:2.23.4")
Expand Down
2 changes: 2 additions & 0 deletions test_runner/src/main/kotlin/ftl/cli/auth/LoginCommand.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package ftl.cli.auth

import ftl.gc.UserAuth
import picocli.CommandLine

@CommandLine.Command(
Expand All @@ -15,6 +16,7 @@ import picocli.CommandLine
)
class LoginCommand : Runnable {
override fun run() {
UserAuth().request()
}

@CommandLine.Option(
Expand Down
21 changes: 16 additions & 5 deletions test_runner/src/main/kotlin/ftl/config/FtlConstants.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,16 @@ import com.google.api.client.googleapis.util.Utils
import com.google.api.client.http.HttpRequestInitializer
import com.google.api.client.http.javanet.NetHttpTransport
import com.google.api.client.json.JsonFactory
import com.google.auth.oauth2.GoogleCredentials
import com.google.auth.oauth2.ServiceAccountCredentials
import ftl.args.AndroidArgs
import ftl.args.IArgs
import ftl.args.IosArgs
import ftl.config.FtlConstants.credential
import ftl.config.FtlConstants.defaultAndroidConfig
import ftl.config.FtlConstants.defaultIosConfig
import ftl.config.FtlConstants.useMock
import ftl.gc.UserAuth
import ftl.http.HttpTimeoutIncrease
import java.nio.file.Path
import java.nio.file.Paths
Expand Down Expand Up @@ -44,7 +50,15 @@ object FtlConstants {
Paths.get(System.getProperty("user.home"), ".config/gcloud/application_default_credentials.json")
}

val credential: HttpRequestInitializer by lazy {
val credential: GoogleCredentials by lazy {
if (UserAuth.exists()) {
UserAuth.load()
} else {
ServiceAccountCredentials.getApplicationDefault()
}
}

val httpCredential: HttpRequestInitializer by lazy {
if (useMock) {
HttpRequestInitializer {}
} else {
Expand All @@ -53,10 +67,7 @@ object FtlConstants {
// https://developers.google.com/identity/protocols/googlescopes
// https://developers.google.com/identity/protocols/application-default-credentials
// https://cloud.google.com/sdk/gcloud/reference/alpha/compute/instances/set-scopes
HttpTimeoutIncrease(
ServiceAccountCredentials.getApplicationDefault()
.createScoped(listOf("https://www.googleapis.com/auth/cloud-platform"))
)
HttpTimeoutIncrease(credential.createScoped(listOf("https://www.googleapis.com/auth/cloud-platform")))
}
}

Expand Down
57 changes: 0 additions & 57 deletions test_runner/src/main/kotlin/ftl/gc/GcAuth.kt

This file was deleted.

1 change: 1 addition & 0 deletions test_runner/src/main/kotlin/ftl/gc/GcStorage.kt
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ object GcStorage {
val storageOptions: StorageOptions by lazy {
val builder = StorageOptions.newBuilder()
if (FtlConstants.useMock) builder.setHost(FtlConstants.localhost)
builder.setCredentials(FtlConstants.credential)

// The oauth lib for user auth needs to be replaced
// https://github.com/TestArmada/flank/issues/464#issuecomment-455227703
Expand Down
4 changes: 2 additions & 2 deletions test_runner/src/main/kotlin/ftl/gc/GcTesting.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,13 @@ import com.google.api.services.testing.Testing
import ftl.config.FtlConstants
import ftl.config.FtlConstants.JSON_FACTORY
import ftl.config.FtlConstants.applicationName
import ftl.config.FtlConstants.credential
import ftl.config.FtlConstants.httpCredential
import ftl.config.FtlConstants.httpTransport

object GcTesting {

val get: Testing by lazy {
val builder = Testing.Builder(httpTransport, JSON_FACTORY, credential)
val builder = Testing.Builder(httpTransport, JSON_FACTORY, httpCredential)
.setApplicationName(applicationName)

if (FtlConstants.useMock) builder.rootUrl = FtlConstants.localhost
Expand Down
4 changes: 2 additions & 2 deletions test_runner/src/main/kotlin/ftl/gc/GcToolResults.kt
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,14 @@ import ftl.args.IArgs
import ftl.config.FtlConstants
import ftl.config.FtlConstants.JSON_FACTORY
import ftl.config.FtlConstants.applicationName
import ftl.config.FtlConstants.credential
import ftl.config.FtlConstants.httpCredential
import ftl.config.FtlConstants.httpTransport
import ftl.http.executeWithRetry

object GcToolResults {

val service: ToolResults by lazy {
val builder = ToolResults.Builder(httpTransport, JSON_FACTORY, credential)
val builder = ToolResults.Builder(httpTransport, JSON_FACTORY, httpCredential)

if (FtlConstants.useMock) builder.rootUrl = FtlConstants.localhost

Expand Down
117 changes: 117 additions & 0 deletions test_runner/src/main/kotlin/ftl/gc/UserAuth.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
package ftl.gc

import ch.qos.logback.classic.Level
import ch.qos.logback.classic.Logger
import com.google.auth.oauth2.ClientId
import com.google.auth.oauth2.MemoryTokensStorage
import com.google.auth.oauth2.UserAuthorizer
import com.google.auth.oauth2.UserCredentials
import ftl.config.FtlConstants
import io.ktor.application.call
import io.ktor.response.respondText
import io.ktor.routing.get
import io.ktor.routing.routing
import io.ktor.server.engine.embeddedServer
import io.ktor.server.netty.Netty
import java.io.FileInputStream
import java.io.FileOutputStream
import java.io.ObjectInputStream
import java.io.ObjectOutputStream
import java.net.URI
import java.nio.file.Path
import java.nio.file.Paths
import java.util.concurrent.TimeUnit
import kotlinx.coroutines.delay
import kotlinx.coroutines.runBlocking
import org.slf4j.LoggerFactory

class UserAuth {

companion object {
private val home = System.getProperty("user.home")!!
private val dotFlank = Paths.get(home, ".flank/")!!
val userToken: Path = Paths.get(dotFlank.toString(), "UserToken")

fun exists() = userToken.toFile().exists()
fun load(): UserCredentials {
return ObjectInputStream(FileInputStream(userToken.toFile())).use {
it.readObject() as UserCredentials
}
}
}

// Silence Jetty logging.
private val logger = LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME) as Logger

init {
logger.level = Level.OFF
}

private var waitingForUserAuth = true

private val server = embeddedServer(Netty, 8085) {
routing {
// 'code' and 'scope' are passed back into the callback as parameters
get("/oauth2callback") {
authCode = call.parameters["code"] ?: ""
call.respondText { "User authorized. Close the browser window." }

waitingForUserAuth = false
}
}
}

var authCode = ""

// https://github.com/bootstraponline/gcloud_cli/blob/40521a6e297830b9f652a9ab4d8002e309b4353a/google-cloud-sdk/platform/gsutil/gslib/utils/system_util.py#L177
private val clientId = ClientId.newBuilder()
.setClientId("32555940559.apps.googleusercontent.com")
.setClientSecret("ZmssLNjJy2998hD4CTg2ejr2")
.build()!!

// https://github.com/bootstraponline/gcloud_cli/blob/e4b5e01610abad2e31d8a6edb20b17b2f84c5395/google-cloud-sdk/lib/googlecloudsdk/core/config.py#L167
private val scopes = listOf("https://www.googleapis.com/auth/cloud-platform")

private val tokenStore = MemoryTokensStorage()
private val authorizer = UserAuthorizer.newBuilder()
.setClientId(clientId)
.setScopes(scopes)
.setTokenStore(tokenStore)
.build()!!
private val userId = "flank"
val uri: URI = URI.create("http://localhost:8085")

private fun printAuthorizationUrl() {
val url = authorizer.getAuthorizationUrl(userId, null, uri)
println("Visit the following URL in your browser:")
println(url)
}

fun request() {
if (FtlConstants.useMock) return
printAuthorizationUrl()

server.start(wait = false)

while (waitingForUserAuth) {
runBlocking { delay(1000) }
}

// trade OAuth2 authorization code for tokens.
//
// https://developers.google.com/gdata/docs/auth/oauth#NoLibrary
authorizer.getAndStoreCredentialsFromCode(userId, authCode, uri)

server.stop(0, 0, TimeUnit.SECONDS)

val userCredential = authorizer.getCredentials(userId)

dotFlank.toFile().mkdirs()
ObjectOutputStream(FileOutputStream(userToken.toFile())).use {
it.writeObject(userCredential)
}

println()
println("User token saved to $userToken")
}
}
13 changes: 4 additions & 9 deletions test_runner/src/test/kotlin/Debug.kt
Original file line number Diff line number Diff line change
@@ -1,14 +1,9 @@
import ftl.Main
import picocli.CommandLine

object Debug {
fun main() {
// GoogleApiLogger.logAllToStdout()

@JvmStatic
@Suppress("UnusedPrivateMember") // Suppress detekt rule
fun main(args: Array<String>) {
// GoogleApiLogger.logAllToStdout()

val arguments = arrayOf("firebase", "test", "android", "run") // for debugging. run test from IntelliJ IDEA
CommandLine.run<Runnable>(Main(), System.out, *arguments)
}
val arguments = arrayOf("firebase", "test", "android", "run") // for debugging. run test from IntelliJ IDEA
CommandLine.run<Runnable>(Main(), System.out, *arguments)
}

0 comments on commit c582cce

Please sign in to comment.