mirror of
https://github.com/TanelOrumaa/Estonian-ID-card-mobile-authenticator-POC.git
synced 2024-12-22 12:30:16 +02:00
Fixed the error handling a bit, added some text to login page
This commit is contained in:
parent
e5931692b6
commit
c232a1f734
@ -68,18 +68,18 @@ class AuthFragment : Fragment() {
|
|||||||
|
|
||||||
override fun onFinish() {
|
override fun onFinish() {
|
||||||
Thread.sleep(750)
|
Thread.sleep(750)
|
||||||
cancelAuth()
|
cancelAuth(408)
|
||||||
}
|
}
|
||||||
}.start()
|
}.start()
|
||||||
// The button exists in code for testing reasons, but not visible to the user anymore unless visibility is changed in the code.
|
// The button exists in code for testing reasons, but not visible to the user anymore unless visibility is changed in the code.
|
||||||
binding.nextButton.visibility = View.GONE
|
binding.nextButton.visibility = View.GONE
|
||||||
binding.nextButton.setOnClickListener { goToNextFragment() }
|
binding.nextButton.setOnClickListener { goToNextFragment() }
|
||||||
binding.cancelButton.setOnClickListener { cancelAuth() }
|
binding.cancelButton.setOnClickListener { cancelAuth(444) }
|
||||||
val adapter = NfcAdapter.getDefaultAdapter(activity)
|
val adapter = NfcAdapter.getDefaultAdapter(activity)
|
||||||
if (adapter != null)
|
if (adapter != null)
|
||||||
getInfoFromIdCard(adapter)
|
getInfoFromIdCard(adapter)
|
||||||
else { // If NFC adapter can not be detected then end the auth process as it is not possible to read an ID card
|
else { // If NFC adapter can not be detected then end the auth process as it is not possible to read an ID card
|
||||||
cancelAuth() // It would be a good idea to show user some notification as it might be confusing if the app suddenly closes
|
cancelAuth(447) // It would be a good idea to show user some notification as it might be confusing if the app suddenly closes
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -89,7 +89,7 @@ class AuthFragment : Fragment() {
|
|||||||
findNavController().navigate(action)
|
findNavController().navigate(action)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun cancelAuth() {
|
private fun cancelAuth(code: Int) {
|
||||||
viewModel.clearUserInfo()
|
viewModel.clearUserInfo()
|
||||||
timer.cancel()
|
timer.cancel()
|
||||||
if (args.mobile) {
|
if (args.mobile) {
|
||||||
@ -97,6 +97,7 @@ class AuthFragment : Fragment() {
|
|||||||
requireActivity().setResult(AppCompatActivity.RESULT_CANCELED, resultIntent)
|
requireActivity().setResult(AppCompatActivity.RESULT_CANCELED, resultIntent)
|
||||||
requireActivity().finish()
|
requireActivity().finish()
|
||||||
} else {
|
} else {
|
||||||
|
(activity as MainActivity).returnError(code)
|
||||||
requireActivity().finishAndRemoveTask()
|
requireActivity().finishAndRemoveTask()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -123,24 +124,28 @@ class AuthFragment : Fragment() {
|
|||||||
}
|
}
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
when(e) {
|
when(e) {
|
||||||
is TagLostException -> requireActivity().runOnUiThread { binding!!.timeCounter.text = getString(R.string.id_card_removed_early) }
|
is TagLostException -> requireActivity().runOnUiThread {
|
||||||
|
binding!!.timeCounter.text = getString(R.string.id_card_removed_early)
|
||||||
|
cancelAuth(444)
|
||||||
|
}
|
||||||
else -> {
|
else -> {
|
||||||
when ("invalid pin") {
|
when ("invalid pin") {
|
||||||
in e.message.toString().lowercase() -> requireActivity().runOnUiThread {
|
in e.message.toString().lowercase() -> requireActivity().runOnUiThread {
|
||||||
val messagePieces = e.message.toString().split(" ")
|
val messagePieces = e.message.toString().split(" ")
|
||||||
binding.timeCounter.text = getString(R.string.wrong_pin, messagePieces[messagePieces.size - 1])
|
binding.timeCounter.text = getString(R.string.wrong_pin, messagePieces[messagePieces.size - 1])
|
||||||
viewModel.deletePin(requireContext())
|
viewModel.deletePin(requireContext())
|
||||||
|
cancelAuth(449)
|
||||||
}
|
}
|
||||||
else -> requireActivity().runOnUiThread {
|
else -> requireActivity().runOnUiThread {
|
||||||
binding.timeCounter.text = getString(R.string.wrong_can_text)
|
binding.timeCounter.text = getString(R.string.wrong_can_text)
|
||||||
viewModel.deleteCan(requireContext())
|
viewModel.deleteCan(requireContext())
|
||||||
|
cancelAuth(449)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Give user some time to read the error message
|
// Give user some time to read the error message
|
||||||
Thread.sleep(2000)
|
Thread.sleep(2000)
|
||||||
cancelAuth()
|
|
||||||
} finally {
|
} finally {
|
||||||
adapter.disableReaderMode(activity)
|
adapter.disableReaderMode(activity)
|
||||||
}
|
}
|
||||||
|
@ -90,6 +90,7 @@ class CanFragment : Fragment() {
|
|||||||
requireActivity().setResult(AppCompatActivity.RESULT_CANCELED, resultIntent)
|
requireActivity().setResult(AppCompatActivity.RESULT_CANCELED, resultIntent)
|
||||||
requireActivity().finish()
|
requireActivity().finish()
|
||||||
} else {
|
} else {
|
||||||
|
(activity as MainActivity).returnError(444)
|
||||||
requireActivity().finishAndRemoveTask()
|
requireActivity().finishAndRemoveTask()
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -5,9 +5,17 @@ import android.os.Bundle
|
|||||||
import android.view.Menu
|
import android.view.Menu
|
||||||
import android.view.MenuItem
|
import android.view.MenuItem
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
|
import androidx.activity.viewModels
|
||||||
|
import androidx.fragment.app.activityViewModels
|
||||||
import androidx.navigation.NavController
|
import androidx.navigation.NavController
|
||||||
import androidx.navigation.fragment.NavHostFragment
|
import androidx.navigation.fragment.NavHostFragment
|
||||||
|
import androidx.navigation.fragment.navArgs
|
||||||
|
import androidx.navigation.navArgs
|
||||||
|
import com.google.gson.JsonObject
|
||||||
|
import com.koushikdutta.ion.Ion
|
||||||
import com.tarkvaraprojekt.mobileauthapp.databinding.ActivityMainBinding
|
import com.tarkvaraprojekt.mobileauthapp.databinding.ActivityMainBinding
|
||||||
|
import com.tarkvaraprojekt.mobileauthapp.databinding.FragmentResultBinding
|
||||||
|
import com.tarkvaraprojekt.mobileauthapp.model.ParametersViewModel
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -16,6 +24,8 @@ import com.tarkvaraprojekt.mobileauthapp.databinding.ActivityMainBinding
|
|||||||
class MainActivity : AppCompatActivity() {
|
class MainActivity : AppCompatActivity() {
|
||||||
|
|
||||||
private lateinit var navigationController: NavController
|
private lateinit var navigationController: NavController
|
||||||
|
private val paramsModel: ParametersViewModel by viewModels()
|
||||||
|
|
||||||
|
|
||||||
// If true the settings menu can be accessed from the toolbar in the upper part of the screen.
|
// If true the settings menu can be accessed from the toolbar in the upper part of the screen.
|
||||||
var menuAvailable: Boolean = true
|
var menuAvailable: Boolean = true
|
||||||
@ -54,4 +64,24 @@ class MainActivity : AppCompatActivity() {
|
|||||||
}
|
}
|
||||||
else -> super.onOptionsItemSelected(item)
|
else -> super.onOptionsItemSelected(item)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun returnError(errorCode: Int) {
|
||||||
|
val json = JsonObject()
|
||||||
|
json.addProperty("auth-token", "")
|
||||||
|
json.addProperty("error", errorCode)
|
||||||
|
|
||||||
|
Ion.getDefault(this).conscryptMiddleware.enable(false)
|
||||||
|
val ion = Ion.with(this)
|
||||||
|
.load(paramsModel.authUrl)
|
||||||
|
for ((header, value) in paramsModel.headers) {
|
||||||
|
ion.setHeader(header, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
ion
|
||||||
|
.setJsonObjectBody(json)
|
||||||
|
.asJsonObject()
|
||||||
|
.setCallback { _, _ ->
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
@ -96,6 +96,7 @@ class PinFragment : Fragment() {
|
|||||||
requireActivity().setResult(AppCompatActivity.RESULT_CANCELED, resultIntent)
|
requireActivity().setResult(AppCompatActivity.RESULT_CANCELED, resultIntent)
|
||||||
requireActivity().finish()
|
requireActivity().finish()
|
||||||
} else {
|
} else {
|
||||||
|
(activity as MainActivity).returnError(444)
|
||||||
requireActivity().finishAndRemoveTask()
|
requireActivity().finishAndRemoveTask()
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -68,8 +68,7 @@ class ResultFragment : Fragment() {
|
|||||||
fun postToken() {
|
fun postToken() {
|
||||||
val json = JsonObject()
|
val json = JsonObject()
|
||||||
json.addProperty("auth-token", paramsModel.token)
|
json.addProperty("auth-token", paramsModel.token)
|
||||||
|
json.addProperty("error", 200)
|
||||||
|
|
||||||
|
|
||||||
Ion.getDefault(activity).conscryptMiddleware.enable(false)
|
Ion.getDefault(activity).conscryptMiddleware.enable(false)
|
||||||
val ion = Ion.with(activity)
|
val ion = Ion.with(activity)
|
||||||
|
2
demoBackend/.gitignore
vendored
2
demoBackend/.gitignore
vendored
@ -33,4 +33,4 @@ build/
|
|||||||
.vscode/
|
.vscode/
|
||||||
|
|
||||||
### web-eid.js ###
|
### web-eid.js ###
|
||||||
!**src/demo-website/src/web-eid.js
|
src/demo-website/src/web-eid.js
|
@ -94,6 +94,7 @@
|
|||||||
<build>
|
<build>
|
||||||
<sourceDirectory>${project.basedir}/src/main/kotlin</sourceDirectory>
|
<sourceDirectory>${project.basedir}/src/main/kotlin</sourceDirectory>
|
||||||
<testSourceDirectory>${project.basedir}/src/test/kotlin</testSourceDirectory>
|
<testSourceDirectory>${project.basedir}/src/test/kotlin</testSourceDirectory>
|
||||||
|
<finalName>demo</finalName>
|
||||||
<plugins>
|
<plugins>
|
||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
30
demoBackend/src/demo-website/package-lock.json
generated
30
demoBackend/src/demo-website/package-lock.json
generated
@ -8,7 +8,7 @@
|
|||||||
"name": "demo-website",
|
"name": "demo-website",
|
||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@web-eid/web-eid-library": "github:TanelOrumaa/web-eid.js#main",
|
"@web-eid/web-eid-library": "../../../../web-eid.js/",
|
||||||
"core-js": "^3.6.5",
|
"core-js": "^3.6.5",
|
||||||
"vue": "^3.0.0",
|
"vue": "^3.0.0",
|
||||||
"vue-cookie-next": "^1.3.0",
|
"vue-cookie-next": "^1.3.0",
|
||||||
@ -32,7 +32,6 @@
|
|||||||
"../../../../web-eid.js": {
|
"../../../../web-eid.js": {
|
||||||
"name": "@web-eid/web-eid-library",
|
"name": "@web-eid/web-eid-library",
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"extraneous": true,
|
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/node": "^16.11.11"
|
"@types/node": "^16.11.11"
|
||||||
@ -1925,7 +1924,8 @@
|
|||||||
"node_modules/@types/node": {
|
"node_modules/@types/node": {
|
||||||
"version": "16.11.12",
|
"version": "16.11.12",
|
||||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-16.11.12.tgz",
|
"resolved": "https://registry.npmjs.org/@types/node/-/node-16.11.12.tgz",
|
||||||
"integrity": "sha512-+2Iggwg7PxoO5Kyhvsq9VarmPbIelXP070HMImEpbtGCoyWNINQj4wzjbQCXzdHTRXnqufutJb5KAURZANNBAw=="
|
"integrity": "sha512-+2Iggwg7PxoO5Kyhvsq9VarmPbIelXP070HMImEpbtGCoyWNINQj4wzjbQCXzdHTRXnqufutJb5KAURZANNBAw==",
|
||||||
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/@types/normalize-package-data": {
|
"node_modules/@types/normalize-package-data": {
|
||||||
"version": "2.4.1",
|
"version": "2.4.1",
|
||||||
@ -2643,12 +2643,8 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/@web-eid/web-eid-library": {
|
"node_modules/@web-eid/web-eid-library": {
|
||||||
"version": "1.0.1",
|
"resolved": "../../../../web-eid.js",
|
||||||
"resolved": "git+ssh://git@github.com/TanelOrumaa/web-eid.js.git#b9c6f50c78a39b444d5df308826cd3f3476233d1",
|
"link": true
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"@types/node": "^16.11.11"
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"node_modules/@webassemblyjs/ast": {
|
"node_modules/@webassemblyjs/ast": {
|
||||||
"version": "1.9.0",
|
"version": "1.9.0",
|
||||||
@ -16604,7 +16600,8 @@
|
|||||||
"@types/node": {
|
"@types/node": {
|
||||||
"version": "16.11.12",
|
"version": "16.11.12",
|
||||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-16.11.12.tgz",
|
"resolved": "https://registry.npmjs.org/@types/node/-/node-16.11.12.tgz",
|
||||||
"integrity": "sha512-+2Iggwg7PxoO5Kyhvsq9VarmPbIelXP070HMImEpbtGCoyWNINQj4wzjbQCXzdHTRXnqufutJb5KAURZANNBAw=="
|
"integrity": "sha512-+2Iggwg7PxoO5Kyhvsq9VarmPbIelXP070HMImEpbtGCoyWNINQj4wzjbQCXzdHTRXnqufutJb5KAURZANNBAw==",
|
||||||
|
"dev": true
|
||||||
},
|
},
|
||||||
"@types/normalize-package-data": {
|
"@types/normalize-package-data": {
|
||||||
"version": "2.4.1",
|
"version": "2.4.1",
|
||||||
@ -17212,10 +17209,17 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"@web-eid/web-eid-library": {
|
"@web-eid/web-eid-library": {
|
||||||
"version": "git+ssh://git@github.com/TanelOrumaa/web-eid.js.git#b9c6f50c78a39b444d5df308826cd3f3476233d1",
|
"version": "file:../../../../web-eid.js",
|
||||||
"from": "@web-eid/web-eid-library@github:TanelOrumaa/web-eid.js#main",
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"@types/node": "^16.11.11"
|
"@types/node": "^16.11.11",
|
||||||
|
"@typescript-eslint/eslint-plugin": "^4.31.2",
|
||||||
|
"@typescript-eslint/parser": "^4.31.2",
|
||||||
|
"eslint": "^7.25.0",
|
||||||
|
"rimraf": "^3.0.2",
|
||||||
|
"rollup": "^2.26.11",
|
||||||
|
"rollup-plugin-polyfill-node": "^0.8.0",
|
||||||
|
"rollup-plugin-terser": "^5.3.1",
|
||||||
|
"typescript": "^3.8.3"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@webassemblyjs/ast": {
|
"@webassemblyjs/ast": {
|
||||||
|
@ -8,7 +8,8 @@
|
|||||||
"lint": "vue-cli-service lint"
|
"lint": "vue-cli-service lint"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@web-eid/web-eid-library": "github:TanelOrumaa/web-eid.js#main",
|
|
||||||
|
"@web-eid/web-eid-library": "../../../../web-eid.js/",
|
||||||
"core-js": "^3.6.5",
|
"core-js": "^3.6.5",
|
||||||
"vue": "^3.0.0",
|
"vue": "^3.0.0",
|
||||||
"vue-cookie-next": "^1.3.0",
|
"vue-cookie-next": "^1.3.0",
|
||||||
|
@ -1,9 +1,15 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="container container-md d-flex flex-column">
|
<div class="container container-md d-flex flex-column">
|
||||||
<div>
|
<div>
|
||||||
<h3 class="text-center">Welcome to Estonian ID card mobile authentication demo website. When using an Android mobile phone, you can
|
<h3 class="text-center">Welcome to Estonian ID card mobile authentication demo website.</h3>
|
||||||
log in to the
|
<p>This website to demonstrates the viability of using your NFC-enabled ID-card and your smartphone to authenticate yourself.
|
||||||
website using your ID card by using the button below.</h3>
|
This is a proof of concept solution, so currently only authentication is supported. This solution was created for <a href="https://courses.cs.ut.ee/2021/tvp/">Software Project (Tarkvaraprojekt)</a> course in the University of Tartu
|
||||||
|
in cooperation with <a href="https://github.com/martinpaljak/">Martin Paljak</a>.</p>
|
||||||
|
<p>This solution is meant to be web-eid.js compatible, so this example website uses a <a href="https://github.com/TanelOrumaa/web-eid.js">fork of web-eid.js</a> which supports the Android authentication app.</p>
|
||||||
|
<h2>Usage</h2>
|
||||||
|
<p>To get started, download and install the authentication Android app from <a href="https://github.com/TanelOrumaa/Estonian-ID-card-mobile-authenticator-POC/releases">GitHub</a> (Android 8.0+ required).
|
||||||
|
You can then click "Login" to authenticate yourself on this demo website with the app or if you are using a non-Android device, you can use both the app or the default web-eid.js option to login using the smartcard reader.
|
||||||
|
</p>
|
||||||
|
|
||||||
<p class="text-center">Read more from <a href="https://github.com/TanelOrumaa/Estonian-ID-card-mobile-authenticator-POC">here.</a></p>
|
<p class="text-center">Read more from <a href="https://github.com/TanelOrumaa/Estonian-ID-card-mobile-authenticator-POC">here.</a></p>
|
||||||
</div>
|
</div>
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -4,7 +4,7 @@ class ApplicationConfiguration {
|
|||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
// URL for application. Use ngrok for HTTPS (or a tool of your own choice) and put the HTTPS link here.
|
// URL for application. Use ngrok for HTTPS (or a tool of your own choice) and put the HTTPS link here.
|
||||||
val WEBSITE_ORIGIN_URL = "https://5a0b-85-253-195-195.ngrok.io"
|
val WEBSITE_ORIGIN_URL = "https://6fa5-145-14-34-146.ngrok.io"
|
||||||
|
|
||||||
// Authentication request timeout in seconds.
|
// Authentication request timeout in seconds.
|
||||||
val AUTH_REQUEST_TIMEOUT_MS = 120000
|
val AUTH_REQUEST_TIMEOUT_MS = 120000
|
||||||
|
@ -19,11 +19,10 @@ class SessionManager {
|
|||||||
private val sessionRegistry = HashMap<String, AuthDto>()
|
private val sessionRegistry = HashMap<String, AuthDto>()
|
||||||
|
|
||||||
fun registerSession(sessionId: String) {
|
fun registerSession(sessionId: String) {
|
||||||
LOG.warn("REGISTERING SESSION $sessionId")
|
|
||||||
if (sessionRegistry.containsKey(sessionId)) {
|
if (sessionRegistry.containsKey(sessionId)) {
|
||||||
LOG.debug("Session already exists.")
|
LOG.debug("Session already exists.")
|
||||||
} else {
|
} else {
|
||||||
sessionRegistry[sessionId] = AuthDto(arrayListOf(), hashMapOf())
|
sessionRegistry[sessionId] = AuthDto(arrayListOf(), hashMapOf(), 200)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -37,6 +36,22 @@ class SessionManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun addErrorToSession(sessionId: String?, authDto: AuthDto) {
|
||||||
|
// Errors are only sent by authentication app, so we can ignore sessionId being null.
|
||||||
|
if (sessionRegistry.containsKey(sessionId)) {
|
||||||
|
sessionRegistry[sessionId]!!.errorCode = authDto.errorCode
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getError(sessionId: String) : Int {
|
||||||
|
if (sessionRegistry.containsKey(sessionId)) {
|
||||||
|
if (sessionRegistry[sessionId]!!.errorCode != 200) {
|
||||||
|
return sessionRegistry[sessionId]!!.errorCode
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 200
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function adds role and userdata specified in authDto to the current session.
|
* Function adds role and userdata specified in authDto to the current session.
|
||||||
*/
|
*/
|
||||||
|
@ -2,4 +2,4 @@ package com.tarkvaratehnika.demobackend.dto
|
|||||||
|
|
||||||
import org.springframework.security.core.GrantedAuthority
|
import org.springframework.security.core.GrantedAuthority
|
||||||
|
|
||||||
data class AuthDto(var roles: ArrayList<GrantedAuthority>, var userData: HashMap<String, String>)
|
data class AuthDto(var roles: ArrayList<GrantedAuthority>, var userData: HashMap<String, String>, var errorCode: Int)
|
@ -2,4 +2,4 @@ package com.tarkvaratehnika.demobackend.dto
|
|||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonProperty
|
import com.fasterxml.jackson.annotation.JsonProperty
|
||||||
|
|
||||||
class AuthTokenDTO (@JsonProperty("auth-token") val token : String)
|
class AuthTokenDTO (@JsonProperty("auth-token") val token : String, val error : Int?)
|
@ -22,12 +22,14 @@
|
|||||||
|
|
||||||
package com.tarkvaratehnika.demobackend.security
|
package com.tarkvaratehnika.demobackend.security
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
|
||||||
import com.tarkvaratehnika.demobackend.config.ApplicationConfiguration
|
import com.tarkvaratehnika.demobackend.config.ApplicationConfiguration
|
||||||
import com.tarkvaratehnika.demobackend.config.ApplicationConfiguration.Companion.USER_ROLE
|
import com.tarkvaratehnika.demobackend.config.ApplicationConfiguration.Companion.USER_ROLE
|
||||||
import com.tarkvaratehnika.demobackend.config.SessionManager
|
import com.tarkvaratehnika.demobackend.config.SessionManager
|
||||||
import com.tarkvaratehnika.demobackend.dto.AuthDto
|
import com.tarkvaratehnika.demobackend.dto.AuthDto
|
||||||
import org.slf4j.LoggerFactory
|
import org.slf4j.LoggerFactory
|
||||||
import org.springframework.http.HttpStatus
|
import org.springframework.http.HttpStatus
|
||||||
|
import org.springframework.http.ResponseEntity
|
||||||
import org.webeid.security.certificate.CertificateData
|
import org.webeid.security.certificate.CertificateData
|
||||||
|
|
||||||
import org.springframework.security.core.Authentication
|
import org.springframework.security.core.Authentication
|
||||||
@ -78,59 +80,46 @@ class WebEidAuthentication(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function for getting a Spring authentication object by supplying a challenge.
|
* Function for getting a Spring authentication object for this session.
|
||||||
* TODO: Figure out a more secure solution in the future.
|
|
||||||
*/
|
*/
|
||||||
fun fromSession(headers: HashMap<String, String>): AuthDto {
|
fun fromSession(headers: HashMap<String, String>): ResponseEntity<String> {
|
||||||
|
val mapper = jacksonObjectMapper()
|
||||||
|
|
||||||
val currentTime = Date()
|
val currentTime = Date()
|
||||||
|
|
||||||
// Get sessionId for current session.
|
// Get sessionId for current session.
|
||||||
var sessionId = SessionManager.getSessionId()
|
var sessionId = SessionManager.getSessionId()
|
||||||
|
|
||||||
if (sessionId == null) {
|
if (sessionId == null) {
|
||||||
LOG.warn("SESSION IS NULL")
|
|
||||||
sessionId = SessionManager.getSessionId(headers)
|
sessionId = SessionManager.getSessionId(headers)
|
||||||
if (sessionId == null) {
|
if (sessionId == null) {
|
||||||
LOG.warn("SESSION IS STILL NULL")
|
return ResponseEntity.status(400).body(mapper.writeValueAsString(400))
|
||||||
throw ResponseStatusException(HttpStatus.FORBIDDEN, "Session ID not found.")
|
|
||||||
}
|
}
|
||||||
LOG.warn("SESSION IS NOW: " + sessionId)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
while (currentTime.time + ApplicationConfiguration.AUTH_REQUEST_TIMEOUT_MS > Date().time) {
|
while (currentTime.time + ApplicationConfiguration.AUTH_REQUEST_TIMEOUT_MS > Date().time) {
|
||||||
Thread.sleep(1000)
|
Thread.sleep(1000)
|
||||||
|
|
||||||
|
// Check if an error has been submitted for this session.
|
||||||
|
val error = SessionManager.getError(sessionId)
|
||||||
|
if (error != 200) {
|
||||||
|
return ResponseEntity.status(error).body(mapper.writeValueAsString(error))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if this session has received a role.
|
||||||
if (SessionManager.getSessionHasRole(sessionId, USER_ROLE)) {
|
if (SessionManager.getSessionHasRole(sessionId, USER_ROLE)) {
|
||||||
// Get AuthDto
|
// Get AuthDto
|
||||||
val auth = SessionManager.getSessionAuth(sessionId)
|
val auth = SessionManager.getSessionAuth(sessionId)
|
||||||
|
|
||||||
// Set role and user data to current session.
|
// Set role and user data to current session.
|
||||||
SessionManager.addRoleToCurrentSession(auth!!)
|
SessionManager.addRoleToCurrentSession(auth!!)
|
||||||
LOG.warn("ROLE ADDED AND LOGGING IN.")
|
return ResponseEntity.status(200).body(mapper.writeValueAsString(auth))
|
||||||
return auth
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// In case of timeout return 408.
|
||||||
|
return ResponseEntity.status(408).body(mapper.writeValueAsString(408))
|
||||||
}
|
}
|
||||||
// if (ThreadLocalRandom.current().nextFloat() < 0.5f) { // TODO: For testing.
|
|
||||||
// return null
|
|
||||||
// }
|
|
||||||
throw ResponseStatusException(HttpStatus.REQUEST_TIMEOUT, "Token not received in time.")
|
|
||||||
}
|
|
||||||
|
|
||||||
// // TODO: DELETE
|
|
||||||
//
|
|
||||||
// const val ROLE_USER: String = "ROLE_USER"
|
|
||||||
// private val USER_ROLE: GrantedAuthority = SimpleGrantedAuthority(ROLE_USER)
|
|
||||||
//
|
|
||||||
// fun addAuth(challenge: String) {
|
|
||||||
// val authorities = arrayListOf<GrantedAuthority>()
|
|
||||||
// authorities.add(USER_ROLE)
|
|
||||||
// val auth = WebEidAuthentication("Somename", "11111111111", authorities)
|
|
||||||
// loggedInUsers[challenge] = auth
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
//
|
|
||||||
// // TODO: DELETE UNTIL
|
|
||||||
|
|
||||||
private fun getPrincipalNameFromCertificate(userCertificate: X509Certificate): String {
|
private fun getPrincipalNameFromCertificate(userCertificate: X509Certificate): String {
|
||||||
return Objects.requireNonNull(CertificateData.getSubjectGivenName(userCertificate)) + " " +
|
return Objects.requireNonNull(CertificateData.getSubjectGivenName(userCertificate)) + " " +
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package com.tarkvaratehnika.demobackend.web.rest
|
package com.tarkvaratehnika.demobackend.web.rest
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
|
||||||
import com.tarkvaratehnika.demobackend.config.SessionManager
|
import com.tarkvaratehnika.demobackend.config.SessionManager
|
||||||
import com.tarkvaratehnika.demobackend.dto.AuthDto
|
import com.tarkvaratehnika.demobackend.dto.AuthDto
|
||||||
import com.tarkvaratehnika.demobackend.dto.AuthTokenDTO
|
import com.tarkvaratehnika.demobackend.dto.AuthTokenDTO
|
||||||
@ -8,6 +9,7 @@ import com.tarkvaratehnika.demobackend.security.WebEidAuthentication
|
|||||||
import org.slf4j.LoggerFactory
|
import org.slf4j.LoggerFactory
|
||||||
import org.springframework.http.HttpStatus
|
import org.springframework.http.HttpStatus
|
||||||
import org.springframework.http.MediaType
|
import org.springframework.http.MediaType
|
||||||
|
import org.springframework.http.ResponseEntity
|
||||||
import org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationToken
|
import org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationToken
|
||||||
import org.springframework.web.bind.annotation.*
|
import org.springframework.web.bind.annotation.*
|
||||||
|
|
||||||
@ -19,12 +21,18 @@ class AuthenticationController {
|
|||||||
|
|
||||||
|
|
||||||
@PostMapping("login", consumes = [MediaType.APPLICATION_JSON_VALUE], produces = [MediaType.APPLICATION_JSON_VALUE])
|
@PostMapping("login", consumes = [MediaType.APPLICATION_JSON_VALUE], produces = [MediaType.APPLICATION_JSON_VALUE])
|
||||||
fun authenticate(@RequestHeader headers: Map<String, String>, @RequestBody body : AuthTokenDTO): AuthDto {
|
fun authenticate(@RequestHeader headers: Map<String, String>, @RequestBody authTokenDTO: AuthTokenDTO): AuthDto {
|
||||||
|
|
||||||
val sessionId = SessionManager.getSessionId(headers)
|
val sessionId = SessionManager.getSessionId(headers)
|
||||||
|
|
||||||
|
// Check if an error occurred in the auth app.
|
||||||
|
if (authTokenDTO.error != null && authTokenDTO.error != 200) {
|
||||||
|
val auth = AuthDto(arrayListOf(), hashMapOf(), authTokenDTO.error)
|
||||||
|
SessionManager.addErrorToSession(sessionId, auth)
|
||||||
|
return auth
|
||||||
|
}
|
||||||
|
|
||||||
// Create Spring Security Authentication object with supplied token as credentials.
|
// Create Spring Security Authentication object with supplied token as credentials.
|
||||||
val auth = PreAuthenticatedAuthenticationToken(null, body)
|
val auth = PreAuthenticatedAuthenticationToken(null, authTokenDTO)
|
||||||
|
|
||||||
// Return authentication object if success.
|
// Return authentication object if success.
|
||||||
return AuthTokenDTOAuthenticationProvider.authenticate(auth, sessionId)
|
return AuthTokenDTOAuthenticationProvider.authenticate(auth, sessionId)
|
||||||
@ -32,7 +40,7 @@ class AuthenticationController {
|
|||||||
|
|
||||||
|
|
||||||
@GetMapping("login", produces = [MediaType.APPLICATION_JSON_VALUE])
|
@GetMapping("login", produces = [MediaType.APPLICATION_JSON_VALUE])
|
||||||
fun getAuthenticated(@RequestHeader headers: HashMap<String, String>) : AuthDto {
|
fun getAuthenticated(@RequestHeader headers: HashMap<String, String>) : ResponseEntity<String> {
|
||||||
return WebEidAuthentication.fromSession(headers)
|
return WebEidAuthentication.fromSession(headers)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user