MOB-55 Added session cookies reading

This commit is contained in:
TanelOrumaa 2021-12-06 23:01:10 +02:00
parent 4096201bef
commit 7482c88a4e
10 changed files with 100 additions and 34 deletions

View File

@ -10,9 +10,10 @@
"dependencies": { "dependencies": {
"@web-eid/web-eid-library": "../../../../web-eid.js/", "@web-eid/web-eid-library": "../../../../web-eid.js/",
"core-js": "^3.6.5", "core-js": "^3.6.5",
"js-cookie": "^3.0.1",
"vue": "^3.0.0", "vue": "^3.0.0",
"vue-cookie-next": "^1.3.0",
"vue-router": "^4.0.0-0", "vue-router": "^4.0.0-0",
"vue3-cookies": "^1.0.6",
"vuex": "^4.0.2", "vuex": "^4.0.2",
"vuex-persistedstate": "^4.1.0" "vuex-persistedstate": "^4.1.0"
}, },
@ -8668,14 +8669,6 @@
"integrity": "sha512-JVAfqNPTvNq3sB/VHQJAFxN/sPgKnsKrCwyRt15zwNCdrMMJDdcEOdubuy+DuJYYdm0ox1J4uzEuYKkN+9yhVg==", "integrity": "sha512-JVAfqNPTvNq3sB/VHQJAFxN/sPgKnsKrCwyRt15zwNCdrMMJDdcEOdubuy+DuJYYdm0ox1J4uzEuYKkN+9yhVg==",
"dev": true "dev": true
}, },
"node_modules/js-cookie": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/js-cookie/-/js-cookie-3.0.1.tgz",
"integrity": "sha512-+0rgsUXZu4ncpPxRL+lNEptWMOWl9etvPHc/koSRp6MPwpRYAhmk0dUG00J4bxVV3r9uUzfo24wW0knS07SKSw==",
"engines": {
"node": ">=12"
}
},
"node_modules/js-message": { "node_modules/js-message": {
"version": "1.0.7", "version": "1.0.7",
"resolved": "https://registry.npmjs.org/js-message/-/js-message-1.0.7.tgz", "resolved": "https://registry.npmjs.org/js-message/-/js-message-1.0.7.tgz",
@ -13982,6 +13975,14 @@
"@vue/shared": "3.2.23" "@vue/shared": "3.2.23"
} }
}, },
"node_modules/vue-cookie-next": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/vue-cookie-next/-/vue-cookie-next-1.3.0.tgz",
"integrity": "sha512-+EinbhSf0c0M8cijCXRVgcvYBIm0lmu3/WKeFUokU93R1J3DxkkBHn5wOc9IyJj9ugAPI0d9EnhcOiOFNA/YVQ==",
"peerDependencies": {
"vue": "^3.1.4"
}
},
"node_modules/vue-eslint-parser": { "node_modules/vue-eslint-parser": {
"version": "7.11.0", "version": "7.11.0",
"resolved": "https://registry.npmjs.org/vue-eslint-parser/-/vue-eslint-parser-7.11.0.tgz", "resolved": "https://registry.npmjs.org/vue-eslint-parser/-/vue-eslint-parser-7.11.0.tgz",
@ -14196,6 +14197,14 @@
"integrity": "sha512-4gDntzrifFnCEvyoO8PqyJDmguXgVPxKiIxrBKjIowvL9l+N66196+72XVYR8BBf1Uv1Fgt3bGevJ+sEmxfZzw==", "integrity": "sha512-4gDntzrifFnCEvyoO8PqyJDmguXgVPxKiIxrBKjIowvL9l+N66196+72XVYR8BBf1Uv1Fgt3bGevJ+sEmxfZzw==",
"dev": true "dev": true
}, },
"node_modules/vue3-cookies": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/vue3-cookies/-/vue3-cookies-1.0.6.tgz",
"integrity": "sha512-a1UvVD0qIgxyOqjlSOwnLnqAnz8ASltugEv8yX+96i/WGZAN9fEDci7xO4HIWZE1uToUnRq9JnFhvfDCSo45OA==",
"dependencies": {
"vue": "^3.0.0"
}
},
"node_modules/vuex": { "node_modules/vuex": {
"version": "4.0.2", "version": "4.0.2",
"resolved": "https://registry.npmjs.org/vuex/-/vuex-4.0.2.tgz", "resolved": "https://registry.npmjs.org/vuex/-/vuex-4.0.2.tgz",
@ -21996,11 +22005,6 @@
"integrity": "sha512-JVAfqNPTvNq3sB/VHQJAFxN/sPgKnsKrCwyRt15zwNCdrMMJDdcEOdubuy+DuJYYdm0ox1J4uzEuYKkN+9yhVg==", "integrity": "sha512-JVAfqNPTvNq3sB/VHQJAFxN/sPgKnsKrCwyRt15zwNCdrMMJDdcEOdubuy+DuJYYdm0ox1J4uzEuYKkN+9yhVg==",
"dev": true "dev": true
}, },
"js-cookie": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/js-cookie/-/js-cookie-3.0.1.tgz",
"integrity": "sha512-+0rgsUXZu4ncpPxRL+lNEptWMOWl9etvPHc/koSRp6MPwpRYAhmk0dUG00J4bxVV3r9uUzfo24wW0knS07SKSw=="
},
"js-message": { "js-message": {
"version": "1.0.7", "version": "1.0.7",
"resolved": "https://registry.npmjs.org/js-message/-/js-message-1.0.7.tgz", "resolved": "https://registry.npmjs.org/js-message/-/js-message-1.0.7.tgz",
@ -26418,6 +26422,12 @@
"@vue/shared": "3.2.23" "@vue/shared": "3.2.23"
} }
}, },
"vue-cookie-next": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/vue-cookie-next/-/vue-cookie-next-1.3.0.tgz",
"integrity": "sha512-+EinbhSf0c0M8cijCXRVgcvYBIm0lmu3/WKeFUokU93R1J3DxkkBHn5wOc9IyJj9ugAPI0d9EnhcOiOFNA/YVQ==",
"requires": {}
},
"vue-eslint-parser": { "vue-eslint-parser": {
"version": "7.11.0", "version": "7.11.0",
"resolved": "https://registry.npmjs.org/vue-eslint-parser/-/vue-eslint-parser-7.11.0.tgz", "resolved": "https://registry.npmjs.org/vue-eslint-parser/-/vue-eslint-parser-7.11.0.tgz",
@ -26585,6 +26595,14 @@
"integrity": "sha512-4gDntzrifFnCEvyoO8PqyJDmguXgVPxKiIxrBKjIowvL9l+N66196+72XVYR8BBf1Uv1Fgt3bGevJ+sEmxfZzw==", "integrity": "sha512-4gDntzrifFnCEvyoO8PqyJDmguXgVPxKiIxrBKjIowvL9l+N66196+72XVYR8BBf1Uv1Fgt3bGevJ+sEmxfZzw==",
"dev": true "dev": true
}, },
"vue3-cookies": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/vue3-cookies/-/vue3-cookies-1.0.6.tgz",
"integrity": "sha512-a1UvVD0qIgxyOqjlSOwnLnqAnz8ASltugEv8yX+96i/WGZAN9fEDci7xO4HIWZE1uToUnRq9JnFhvfDCSo45OA==",
"requires": {
"vue": "^3.0.0"
}
},
"vuex": { "vuex": {
"version": "4.0.2", "version": "4.0.2",
"resolved": "https://registry.npmjs.org/vuex/-/vuex-4.0.2.tgz", "resolved": "https://registry.npmjs.org/vuex/-/vuex-4.0.2.tgz",

View File

@ -10,9 +10,10 @@
"dependencies": { "dependencies": {
"@web-eid/web-eid-library": "../../../../web-eid.js/", "@web-eid/web-eid-library": "../../../../web-eid.js/",
"core-js": "^3.6.5", "core-js": "^3.6.5",
"js-cookie": "^3.0.1",
"vue": "^3.0.0", "vue": "^3.0.0",
"vue-cookie-next": "^1.3.0",
"vue-router": "^4.0.0-0", "vue-router": "^4.0.0-0",
"vue3-cookies": "^1.0.6",
"vuex": "^4.0.2", "vuex": "^4.0.2",
"vuex-persistedstate": "^4.1.0" "vuex-persistedstate": "^4.1.0"
}, },

View File

@ -8,7 +8,7 @@
<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>
<div class="justify-content-center d-flex"> <div class="justify-content-center d-flex">
<div id="canvas"></div>
<button type="button" class="btn loginButton btn-dark" v-on:click="authenticate"> <button type="button" class="btn loginButton btn-dark" v-on:click="authenticate">
<div v-if="loading" class="d-flex justify-content-center"> <div v-if="loading" class="d-flex justify-content-center">
<div class="spinner-border text-light spinner-border-sm" role="status"> <div class="spinner-border text-light spinner-border-sm" role="status">
@ -26,7 +26,7 @@
<input type="radio" class="btn-check" name="btnradio" id="btnApp" autocomplete="off" checked v-on:click="useApp"> <input type="radio" class="btn-check" name="btnradio" id="btnApp" autocomplete="off" checked v-on:click="useApp">
<label class="btn btn-outline-secondary" for="btnApp">using Android App</label> <label class="btn btn-outline-secondary" for="btnApp">using Android App</label>
</div> </div>
<div id="canvas"></div>
</div> </div>
</template> </template>
@ -66,7 +66,7 @@ export default {
getAuthSuccessUrl: window.location.origin + "/auth/login", getAuthSuccessUrl: window.location.origin + "/auth/login",
useAuthApp: this.useAndroidApp, useAuthApp: this.useAndroidApp,
headers: { headers: {
[this.csrfHeaderName]: this.csrftoken "sessionId": this.$store.getters.getSessionId
}, },
}; };
@ -90,7 +90,7 @@ export default {
}, },
computed: { computed: {
isLoggedIn() { isLoggedIn() {
return this.$store.authenticated; return this.$store.getAuthenticated;
}, },
loading() { loading() {
return this.loading; return this.loading;
@ -112,6 +112,10 @@ export default {
.loginButton > p { .loginButton > p {
font-size: 3vh; font-size: 3vh;
text-align: center; text-align: center;
}
#canvas {
height: 5vh;
width: 5vh;
} }
</style> </style>

View File

@ -25,6 +25,12 @@ export default {
this.$store.commit("setLoggedIn", false); this.$store.commit("setLoggedIn", false);
router.push("/"); router.push("/");
} }
},
mounted() {
if (this.$store.getters.getSessionId == null) {
const sessionId = this.$cookie.getCookie("JSESSIONID");
this.$store.dispatch("fetchSessionId", sessionId);
}
} }
} }
</script> </script>

View File

@ -1,8 +1,10 @@
import {createApp} from 'vue'; import {createApp} from 'vue';
import App from './App.vue'; import App from './App.vue';
import {createStore} from 'vuex' import {createStore} from 'vuex';
import BootstrapVue3 from 'bootstrap-vue-3' import BootstrapVue3 from 'bootstrap-vue-3';
import createPersistedState from "vuex-persistedstate"; import createPersistedState from "vuex-persistedstate";
import { VueCookieNext } from 'vue-cookie-next'
import 'bootstrap/dist/css/bootstrap.css' import 'bootstrap/dist/css/bootstrap.css'
import 'bootstrap-vue-3/dist/bootstrap-vue-3.css' import 'bootstrap-vue-3/dist/bootstrap-vue-3.css'
@ -13,17 +15,28 @@ const store = createStore({
state() { state() {
return { return {
authenticated: false, authenticated: false,
jSessionId: null,
} }
}, },
mutations: { mutations: {
setLoggedIn(state, isLoggedIn) { setLoggedIn(state, isLoggedIn) {
console.log("Setting logged in: " + isLoggedIn);
state.authenticated = isLoggedIn; state.authenticated = isLoggedIn;
},
setSessionId(state, sessionId) {
state.jSessionId = sessionId;
}
},
actions: {
fetchSessionId(context, sessionId) {
context.commit("setSessionId", sessionId);
} }
}, },
getters: { getters: {
getAuthenticated: state => { getAuthenticated: state => {
return state.authenticated; return state.authenticated;
},
getSessionId: state => {
return state.jSessionId;
} }
}, },
plugins: [createPersistedState()], plugins: [createPersistedState()],
@ -47,4 +60,7 @@ const app = createApp(App)
app.use(BootstrapVue3) app.use(BootstrapVue3)
app.use(router) app.use(router)
app.use(store) app.use(store)
app.use(VueCookieNext);
app.mount('#app') app.mount('#app')
VueCookieNext.config({ expire: '7d' })

View File

@ -1,6 +1,4 @@
package com.tarkvaratehnika.demobackend.security package com.tarkvaratehnika.demobackend.security
import com.fasterxml.jackson.annotation.JsonProperty class AuthTokenDTO (val token : String, val xsrfToken : String) {
class AuthTokenDTO (val token : String, val challenge : String) {
} }

View File

@ -54,13 +54,13 @@ object AuthTokenDTOAuthenticationProvider {
fun authenticate(auth : Authentication) : Authentication { fun authenticate(auth : Authentication) : Authentication {
val authentication = auth as PreAuthenticatedAuthenticationToken val authentication = auth as PreAuthenticatedAuthenticationToken
val token = (authentication.credentials as AuthTokenDTO).token val token = (authentication.credentials as AuthTokenDTO).token
val challenge = (authentication.credentials as AuthTokenDTO).challenge val challenge = (authentication.credentials as AuthTokenDTO)
val authorities = arrayListOf<GrantedAuthority>() val authorities = arrayListOf<GrantedAuthority>()
authorities.add(USER_ROLE) authorities.add(USER_ROLE)
try { try {
val userCertificate: X509Certificate = tokenValidator.validate(token) val userCertificate: X509Certificate = tokenValidator.validate(token)
return WebEidAuthentication.fromCertificate(userCertificate, authorities, challenge) return WebEidAuthentication.fromCertificate(userCertificate, authorities, "as")
} catch (e : TokenValidationException) { } catch (e : TokenValidationException) {
// Validation failed. // Validation failed.
throw AuthenticationServiceException("Token validation failed. " + e.message) throw AuthenticationServiceException("Token validation failed. " + e.message)

View File

@ -0,0 +1,21 @@
package com.tarkvaratehnika.demobackend.security
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder
import org.springframework.security.config.annotation.web.builders.HttpSecurity
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter
import org.springframework.security.config.http.SessionCreationPolicy
@EnableWebSecurity
class SecurityConfiguration : WebSecurityConfigurerAdapter() {
override fun configure(auth: AuthenticationManagerBuilder?) {
auth?.inMemoryAuthentication()?.withUser("justSomeUser")?.password("someBackdoorPasswordThisDoesntMatterItsADemo")
?.roles("USER")
}
override fun configure(http: HttpSecurity?) {
http?.sessionManagement()?.sessionCreationPolicy(SessionCreationPolicy.ALWAYS);
http?.authorizeRequests()?.antMatchers("/**")?.permitAll()
}
}

View File

@ -18,7 +18,7 @@ class AuthenticationController {
private val LOG = LoggerFactory.getLogger(AuthenticationController::class.java) private val LOG = LoggerFactory.getLogger(AuthenticationController::class.java)
@PostMapping("authentication", consumes = [MediaType.APPLICATION_JSON_VALUE], produces = [MediaType.APPLICATION_JSON_VALUE]) @PostMapping("login", consumes = [MediaType.APPLICATION_JSON_VALUE], produces = [MediaType.APPLICATION_JSON_VALUE])
fun authenticate(@RequestBody body : String): Authentication { fun authenticate(@RequestBody body : String): Authentication {
val parts = body.split("\"") val parts = body.split("\"")
val authToken = AuthTokenDTO(parts[3], parts[7]) val authToken = AuthTokenDTO(parts[3], parts[7])
@ -29,9 +29,10 @@ class AuthenticationController {
return AuthTokenDTOAuthenticationProvider.authenticate(auth) return AuthTokenDTOAuthenticationProvider.authenticate(auth)
} }
@GetMapping("authentication", produces = [MediaType.APPLICATION_JSON_VALUE])
@GetMapping("login", produces = [MediaType.APPLICATION_JSON_VALUE])
fun getAuthenticated(headers: String) : Authentication? { fun getAuthenticated(headers: String) : Authentication? {
val auth = WebEidAuthentication.fromChallenge(challenge) val auth = WebEidAuthentication.fromChallenge("as")
if (auth == null) { if (auth == null) {
throw ResponseStatusException(HttpStatus.FORBIDDEN, "Not allowed.") throw ResponseStatusException(HttpStatus.FORBIDDEN, "Not allowed.")
} }

View File

@ -1 +1,2 @@
server.servlet.session.cookie.http-only=false