Skip to content

Commit

Permalink
Enable username password authentication
Browse files Browse the repository at this point in the history
  • Loading branch information
joelhandwell committed Jun 12, 2019
1 parent fcbb1c6 commit e62a8ed
Show file tree
Hide file tree
Showing 8 changed files with 150 additions and 24 deletions.
16 changes: 11 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,17 @@ dependencies {
Then in your kotlin code,

```kotlin
fun main(){
val accessKey = "7283dac8472d4e5d..."
val populi = Populi.Builder().withBaseUrl("https://your_university.populiweb.com/").withAccessKey(accessKey).build()
val degrees = populi.getDegrees()
println(degrees)
fun clientWithUsernamePassword(){
val populi = Populi.Builder().withBaseUrl("https://your_university.populiweb.com/")
.withUsername("your_name")
.withPassword("your_password").build()
println(populi.getDegrees())
}

fun clientWithAccessKey(){
val populi = Populi.Builder().withBaseUrl("https://your_university.populiweb.com/")
.withAccessKey("7283dac8472d4e5d...").build()
println(populi.getDegrees())
}
```

Expand Down
4 changes: 2 additions & 2 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ plugins {
}

group 'com.github.joelhandwell'
version '1.0.1'
version '1.0.2'

repositories {
jcenter()
Expand All @@ -42,7 +42,7 @@ dependencies {
testImplementation 'com.github.tomakehurst:wiremock:2.23.2'

// log
testImplementation 'ch.qos.logback:logback-classic:1.2.3'
implementation 'ch.qos.logback:logback-classic:1.2.3'
}

test {
Expand Down
47 changes: 38 additions & 9 deletions src/main/kotlin/com/github/joelhandwell/populi/client.kt
Original file line number Diff line number Diff line change
@@ -1,22 +1,32 @@
package com.github.joelhandwell.populi

import org.slf4j.Logger
import retrofit2.Call
import retrofit2.Retrofit
import retrofit2.converter.jaxb.JaxbConverterFactory
import retrofit2.http.Field
import retrofit2.http.FormUrlEncoded
import retrofit2.http.POST
import org.slf4j.LoggerFactory

inline fun <reified R : Any> R.logger(): Logger =
LoggerFactory.getLogger(this::class.java.name.substringBefore("\$Companion"))

class Populi(
private val accessKey: String
private val accessKey: String, private val api: PopuliApi
) {

var api: PopuliApi? = null
companion object {
private val log = logger()
}

class Builder {
private var username: String? = null
private var password: String? = null
private var accessKey: String? = null
private var baseUrl: String? = null

fun withUsername(username: String) = apply { this.username = username }
fun withPassword(password: String) = apply { this.password = password }
fun withAccessKey(accessKey: String) = apply { this.accessKey = accessKey }
fun withBaseUrl(baseUrl: String) = apply { this.baseUrl = baseUrl }
fun build(): Populi {
Expand All @@ -25,17 +35,36 @@ class Populi(
.addConverterFactory(JaxbConverterFactory.create())
.build().create(PopuliApi::class.java)

val client = Populi(accessKey ?: throw RuntimeException("accessKey is null"))
client.api = api
return client
if (accessKey == null) {
log.info("fetching accessKey with username and password")
val response = api.requestAccessKey(
username ?: throw RuntimeException("username null"),
password ?: throw RuntimeException("password null")
).execute()
if (!response.isSuccessful) {
throw RuntimeException("accessKey request not success, error body: ${response.errorBody()}")
}
val body = response.body() ?: throw RuntimeException("accessKey response body was null")
if (body.access_key.isNullOrBlank()) {
throw RuntimeException("accessKey was null or blank")
} else {
log.info("We got accessKey!")
}
accessKey = body.access_key.trim()
} else {
log.info("using existing accessKey")
}

return Populi(accessKey!!, api)
}
}

fun getDegrees(): MutableList<Degree>? = this.api!!.getDegrees(accessKey).execute().body()!!.degree
}

interface PopuliApi {
@FormUrlEncoded
@POST("api/")
fun getDegrees(@Field("access_key") accessKey: String, @Field("task") task: String = "getDegrees"): Call<DegreeRequest>

@FormUrlEncoded @POST("api/") fun requestAccessKey(@Field("username") username: String, @Field("password") password: String): Call<AccessKeyResponse>

@FormUrlEncoded @POST("api/") fun getDegrees(@Field("access_key") accessKey: String, @Field("task") task: String = "getDegrees"): Call<DegreeResponse>
}
13 changes: 12 additions & 1 deletion src/main/kotlin/com/github/joelhandwell/populi/model.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,17 @@ package com.github.joelhandwell.populi

import javax.xml.bind.annotation.*

@XmlRootElement(name = "account_id")
class AccountId(var id: Int)

@XmlRootElement(name = "response")
@XmlAccessorType(XmlAccessType.FIELD)
class AccessKeyResponse(
var access_key: String,
var account_id: AccountId,
var account_type: String
)

@XmlRootElement(name = "specialization")
data class Specialization(
var id: Int,
Expand Down Expand Up @@ -34,6 +45,6 @@ data class Degree(
)

@XmlRootElement(name = "response")
data class DegreeRequest(
data class DegreeResponse(
var degree: MutableList<Degree> = mutableListOf()
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package com.github.joelhandwell.populi

import org.spekframework.spek2.Spek
import org.spekframework.spek2.style.specification.describe
import java.io.StringWriter
import javax.xml.bind.JAXB
import kotlin.test.assertEquals

object AccessKeyRequestSpec : Spek({
describe("AccessKeyResponse"){

it("marshal AccessKeyResponse"){
val accessKeyResponse = AccessKeyResponse("AAABBB", AccountId(1111), "PERSON")
val sw = StringWriter()
JAXB.marshal(accessKeyResponse, sw)
val xml = """
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<response>
<access_key>AAABBB</access_key>
<account_id>
<id>1111</id>
</account_id>
<account_type>PERSON</account_type>
</response>
""".trimIndent()
assertEquals(xml.trim(), sw.toString().trim())
}

it("unmarshal AccessKeyResponse"){
val xml = """
<response>
<access_key>
32AD2d3432...REALLYLONGSTRINGOFCHARACTERS...232as72asdf3
</access_key>
<account_id>
<id>2222</id>
</account_id>
<account_type>PERSON</account_type>
</response>
""".trimIndent()
val r = JAXB.unmarshal(xml.reader(), AccessKeyResponse::class.java)
assertEquals("32AD2d3432...REALLYLONGSTRINGOFCHARACTERS...232as72asdf3", r.access_key.trim())
assertEquals(2222, r.account_id.id)
assertEquals("PERSON", r.account_type)
}
}
})
34 changes: 29 additions & 5 deletions src/test/kotlin/com/github/joelhandwell/populi/ClientSpec.kt
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ const val apiAccessKey =
"694f1f255a606e89bd6acc9cdc215c277e7bfd5a326fe057d99903606562cd7f1d37bbf4631c42773321e41ed0f7241decfff04eb8bdac6dfa6b14fc9171086626a22091dd35b7a99db5d24a3df4daa094c16e0b74f5a9ecd8bfc584c13d6f2e5c2719692416cce27d49638ac88a4a8921c7c437c40d4f4ab219fb7fcd5903a8533873c40bb7cda456ff6fd71992403450b3096d5898b40ed2b5983ef970c5e68f5ace7507517283dac8472d4e2d"

object ClientSpec : Spek({

describe("Client") {
(LoggerFactory.getLogger("org.eclipse.jetty") as ch.qos.logback.classic.Logger).level = Level.INFO
val wireMockServer = WireMockServer()
Expand All @@ -25,12 +26,35 @@ object ClientSpec : Spek({
.willReturn(WireMock.aResponse().withBodyFile("getDegrees.xml"))
)

val populi = Populi.Builder().withBaseUrl("http://localhost:$wireMockPort/").withAccessKey(apiAccessKey).build()
val degrees = populi.getDegrees()
assertNotNull(degrees)
assertDegreeRequest(degrees)
val populi = Populi.Builder()
.withBaseUrl("http://localhost:$wireMockPort/")
.withAccessKey(apiAccessKey).build()
assertGetDegrees(populi)
}

it("creates api client with username and password") {
WireMock.stubFor(
WireMock.post("/api/").withRequestBody(WireMock.containing("username=john&password=pass"))
.willReturn(WireMock.aResponse().withBodyFile("accessKeyRequest.xml"))
)

val populi = Populi.Builder().withBaseUrl("http://localhost:$wireMockPort/").withUsername("john")
.withPassword("pass").build()

WireMock.stubFor(
WireMock.post("/api/").withRequestBody(WireMock.containing("access_key=$apiAccessKey&task=getDegrees"))
.willReturn(WireMock.aResponse().withBodyFile("getDegrees.xml"))
)

assertGetDegrees(populi)
}

afterGroup { wireMockServer.stop() }
}
})
})

fun assertGetDegrees(populi: Populi) {
val degrees = populi.getDegrees()
assertNotNull(degrees)
assertDegreeRequest(degrees)
}
4 changes: 2 additions & 2 deletions src/test/kotlin/com/github/joelhandwell/populi/DegreeSpec.kt
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ object DegreeSpec : Spek({
assertDegree(d)
}

it("unmarshal to DegreeRequest") {
it("unmarshal to DegreeResponse") {
val xml = """
<request>
<degree>
Expand Down Expand Up @@ -156,7 +156,7 @@ object DegreeSpec : Spek({
</request>
""".trimIndent()

val dr = JAXB.unmarshal(xml.reader(), DegreeRequest::class.java)
val dr = JAXB.unmarshal(xml.reader(), DegreeResponse::class.java)
assertDegreeRequest(dr.degree)
}
}
Expand Down
9 changes: 9 additions & 0 deletions src/test/resources/__files/accessKeyRequest.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<response>
<access_key>
694f1f255a606e89bd6acc9cdc215c277e7bfd5a326fe057d99903606562cd7f1d37bbf4631c42773321e41ed0f7241decfff04eb8bdac6dfa6b14fc9171086626a22091dd35b7a99db5d24a3df4daa094c16e0b74f5a9ecd8bfc584c13d6f2e5c2719692416cce27d49638ac88a4a8921c7c437c40d4f4ab219fb7fcd5903a8533873c40bb7cda456ff6fd71992403450b3096d5898b40ed2b5983ef970c5e68f5ace7507517283dac8472d4e2d
</access_key>
<account_id>
<id>2222</id>
</account_id>
<account_type>PERSON</account_type>
</response>

0 comments on commit e62a8ed

Please sign in to comment.