Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature - add interactive login page #1

Merged
merged 10 commits into from
Mar 21, 2020
3 changes: 2 additions & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ val jacksonVersion = "2.10.1"
val junitJupiterVersion = "5.5.2"
val konfigVersion = "1.6.10.0"
val kotlinVersion = "1.3.61"

val freemarkerVersion = "2.3.29"
val mavenRepoBaseUrl = "https://oss.sonatype.org"
val mainClassKt = "no.nav.security.mock.StandaloneMockOAuth2ServerKt"

Expand Down Expand Up @@ -54,6 +54,7 @@ dependencies {
api("com.nimbusds:oauth2-oidc-sdk:$nimbusSdkVersion")
implementation("io.github.microutils:kotlin-logging:$kotlinLoggingVersion")
implementation("com.fasterxml.jackson.module:jackson-module-kotlin:$jacksonVersion")
implementation("org.freemarker:freemarker:$freemarkerVersion")
testImplementation("org.assertj:assertj-core:$assertjVersion")
testImplementation("org.junit.jupiter:junit-jupiter-api:$junitJupiterVersion")
testImplementation("org.jetbrains.kotlin:kotlin-test-junit5:$kotlinVersion")
Expand Down
76 changes: 0 additions & 76 deletions src/main/kotlin/no/nav/security/mock/MockOAuth2Server.kt

This file was deleted.

This file was deleted.

This file was deleted.

106 changes: 106 additions & 0 deletions src/main/kotlin/no/nav/security/mock/oauth2/MockOAuth2Server.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
package no.nav.security.mock.oauth2

import com.nimbusds.jwt.SignedJWT
import com.nimbusds.oauth2.sdk.AuthorizationCode
import com.nimbusds.oauth2.sdk.AuthorizationCodeGrant
import com.nimbusds.oauth2.sdk.TokenRequest
import com.nimbusds.oauth2.sdk.auth.ClientSecretBasic
import com.nimbusds.oauth2.sdk.auth.Secret
import com.nimbusds.oauth2.sdk.id.ClientID
import mu.KotlinLogging
import no.nav.security.mock.oauth2.extensions.asOAuth2HttpRequest
import no.nav.security.mock.oauth2.extensions.toAuthorizationEndpointUrl
import no.nav.security.mock.oauth2.extensions.toJwksUrl
import no.nav.security.mock.oauth2.extensions.toTokenEndpointUrl
import no.nav.security.mock.oauth2.extensions.toWellKnownUrl
import no.nav.security.mock.oauth2.http.OAuth2HttpRequestHandler
import no.nav.security.mock.oauth2.http.OAuth2HttpResponse
import no.nav.security.mock.oauth2.token.OAuth2TokenCallback
import no.nav.security.mock.oauth2.token.OAuth2TokenProvider
import okhttp3.HttpUrl
import okhttp3.mockwebserver.Dispatcher
import okhttp3.mockwebserver.MockResponse
import okhttp3.mockwebserver.MockWebServer
import okhttp3.mockwebserver.RecordedRequest
import java.io.IOException
import java.net.InetSocketAddress
import java.net.URI
import java.util.concurrent.BlockingQueue
import java.util.concurrent.LinkedBlockingQueue

private val log = KotlinLogging.logger {}

class MockOAuth2Server(
config: OAuth2Config = OAuth2Config()
) {
private val mockWebServer: MockWebServer = MockWebServer()
private val tokenProvider: OAuth2TokenProvider =
OAuth2TokenProvider()

var dispatcher: Dispatcher = MockOAuth2Dispatcher(config)

fun start() {
mockWebServer.start()
mockWebServer.dispatcher = dispatcher
}

fun start(port: Int = 0) {
val address = InetSocketAddress(0).address
log.info("attempting to start server on port $port and InetAddress=$address")
mockWebServer.start(address, port)
mockWebServer.dispatcher = dispatcher
}

@Throws(IOException::class)
fun shutdown() {
mockWebServer.shutdown()
}

fun url(path: String): HttpUrl = mockWebServer.url(path)
fun enqueueResponse(response: MockResponse) = (dispatcher as MockOAuth2Dispatcher).enqueueResponse(response)
fun enqueueCallback(oAuth2TokenCallback: OAuth2TokenCallback) = (dispatcher as MockOAuth2Dispatcher).enqueueTokenCallback(oAuth2TokenCallback)
fun takeRequest(): RecordedRequest = mockWebServer.takeRequest()

fun wellKnownUrl(issuerId: String): HttpUrl = mockWebServer.url(issuerId).toWellKnownUrl()
fun tokenEndpointUrl(issuerId: String): HttpUrl = mockWebServer.url(issuerId).toTokenEndpointUrl()
fun jwksUrl(issuerId: String): HttpUrl = mockWebServer.url(issuerId).toJwksUrl()
fun issuerUrl(issuerId: String): HttpUrl = mockWebServer.url(issuerId)
fun authorizationEndpointUrl(issuerId: String): HttpUrl = mockWebServer.url(issuerId).toAuthorizationEndpointUrl()
fun baseUrl(): HttpUrl = mockWebServer.url("")

fun issueToken(issuerId: String, clientId: String, OAuth2TokenCallback: OAuth2TokenCallback): SignedJWT {
val uri = tokenEndpointUrl(issuerId)
val issuerUrl = issuerUrl(issuerId)
val tokenRequest = TokenRequest(
uri.toUri(),
ClientSecretBasic(ClientID(clientId), Secret("secret")),
AuthorizationCodeGrant(AuthorizationCode("123"), URI.create("http://localhost"))
)
return tokenProvider.accessToken(tokenRequest, issuerUrl, null, OAuth2TokenCallback)
}
}

class MockOAuth2Dispatcher(
config: OAuth2Config
) : Dispatcher() {
private val httpRequestHandler: OAuth2HttpRequestHandler = OAuth2HttpRequestHandler(config)
private val responseQueue: BlockingQueue<MockResponse> = LinkedBlockingQueue()

fun enqueueResponse(mockResponse: MockResponse) = responseQueue.add(mockResponse)
fun enqueueTokenCallback(oAuth2TokenCallback: OAuth2TokenCallback) = httpRequestHandler.enqueueTokenCallback(oAuth2TokenCallback)

override fun dispatch(request: RecordedRequest): MockResponse =
when {
responseQueue.peek() != null -> responseQueue.take()
else -> mockResponse(httpRequestHandler.handleRequest(request.asOAuth2HttpRequest()))
}


private fun mockResponse(response: OAuth2HttpResponse): MockResponse =
MockResponse()
.setHeaders(response.headers)
.setResponseCode(response.status)
.apply {
response.body?.let { this.setBody(it) }
}
}
10 changes: 10 additions & 0 deletions src/main/kotlin/no/nav/security/mock/oauth2/OAuth2Config.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package no.nav.security.mock.oauth2

import no.nav.security.mock.oauth2.token.OAuth2TokenCallback
import no.nav.security.mock.oauth2.token.OAuth2TokenProvider

data class OAuth2Config(
val interactiveLogin: Boolean = false,
val tokenProvider: OAuth2TokenProvider = OAuth2TokenProvider(),
val oAuth2TokenCallbacks: Set<OAuth2TokenCallback> = emptySet()
)
Loading