diff options
author | Yigit Sever | 2021-04-14 03:27:27 +0300 |
---|---|---|
committer | Yigit Sever | 2021-04-14 19:11:49 +0300 |
commit | e466f25ecfa356137523ee597b9fc6ab0da5df22 (patch) | |
tree | 06946f8811f90cf89ddc0afe685f15e9b3cf6cda /src | |
parent | db5a025bae30bfb6044e87eb196cc6bb63eb68d3 (diff) | |
download | gradecoin-e466f25ecfa356137523ee597b9fc6ab0da5df22.tar.gz gradecoin-e466f25ecfa356137523ee597b9fc6ab0da5df22.tar.bz2 gradecoin-e466f25ecfa356137523ee597b9fc6ab0da5df22.zip |
[WIP] Initial implementation of user auth
There is a dance involved and everything
Write down specs for RSA and AES, padding scheme, ugh.
Diffstat (limited to 'src')
-rw-r--r-- | src/custom_filters.rs | 8 | ||||
-rw-r--r-- | src/handlers.rs | 34 | ||||
-rw-r--r-- | src/lib.rs | 40 | ||||
-rw-r--r-- | src/schema.rs | 9 |
4 files changed, 83 insertions, 8 deletions
diff --git a/src/custom_filters.rs b/src/custom_filters.rs index ae8a56c..299cd8d 100644 --- a/src/custom_filters.rs +++ b/src/custom_filters.rs | |||
@@ -1,5 +1,5 @@ | |||
1 | /// Functions that extracts Structs to be used in warp routines | 1 | /// Functions that extracts Structs to be used in warp routines |
2 | use crate::schema::{AuthRequest, Block, Db, Transaction}; | 2 | use crate::schema::{Block, Db, InitialAuthRequest, Transaction}; |
3 | use std::convert::Infallible; | 3 | use std::convert::Infallible; |
4 | use warp::{Filter, Rejection}; | 4 | use warp::{Filter, Rejection}; |
5 | 5 | ||
@@ -8,12 +8,12 @@ pub fn with_db(db: Db) -> impl Filter<Extract = (Db,), Error = Infallible> + Clo | |||
8 | warp::any().map(move || db.clone()) | 8 | warp::any().map(move || db.clone()) |
9 | } | 9 | } |
10 | 10 | ||
11 | /// Extracts an `AuthRequest` JSON body from the request | 11 | /// Extracts an `InitialAuthRequest` JSON body from the request |
12 | /// Accepts only JSON encoded `AuthRequest` body and rejects big payloads | 12 | /// Accepts only JSON encoded `AuthRequest` body and rejects big payloads |
13 | /// | 13 | /// |
14 | // TODO: find a good limit for this, (=e2482057; 8 char String + rsa pem) <11-04-21, yigit> // | 14 | // TODO: find a good limit for this, (=e2482057; 8 char String + rsa pem) <11-04-21, yigit> // |
15 | pub fn auth_request_json_body() -> impl Filter<Extract = (AuthRequest,), Error = Rejection> + Clone | 15 | pub fn auth_request_json_body( |
16 | { | 16 | ) -> impl Filter<Extract = (InitialAuthRequest,), Error = Rejection> + Clone { |
17 | warp::body::content_length_limit(1024 * 32).and(warp::body::json()) | 17 | warp::body::content_length_limit(1024 * 32).and(warp::body::json()) |
18 | } | 18 | } |
19 | 19 | ||
diff --git a/src/handlers.rs b/src/handlers.rs index b9df931..9d1bb10 100644 --- a/src/handlers.rs +++ b/src/handlers.rs | |||
@@ -1,3 +1,4 @@ | |||
1 | use base64; | ||
1 | /// API handlers, the ends of each filter chain | 2 | /// API handlers, the ends of each filter chain |
2 | use blake2::{Blake2s, Digest}; | 3 | use blake2::{Blake2s, Digest}; |
3 | use jsonwebtoken::errors::ErrorKind; | 4 | use jsonwebtoken::errors::ErrorKind; |
@@ -5,12 +6,16 @@ use jsonwebtoken::{decode, Algorithm, DecodingKey, TokenData, Validation}; | |||
5 | use log::{debug, warn}; | 6 | use log::{debug, warn}; |
6 | use md5::Md5; | 7 | use md5::Md5; |
7 | use parking_lot::RwLockUpgradableReadGuard; | 8 | use parking_lot::RwLockUpgradableReadGuard; |
9 | use rsa::{PaddingScheme, RSAPrivateKey}; | ||
8 | use serde::Serialize; | 10 | use serde::Serialize; |
9 | use serde_json; | 11 | use serde_json; |
12 | use sha2; | ||
10 | use std::convert::Infallible; | 13 | use std::convert::Infallible; |
11 | use std::fs; | 14 | use std::fs; |
12 | use warp::{http::StatusCode, reply}; | 15 | use warp::{http::StatusCode, reply}; |
13 | 16 | ||
17 | use crate::PRIVATE_KEY; | ||
18 | |||
14 | #[derive(Serialize, Debug)] | 19 | #[derive(Serialize, Debug)] |
15 | struct GradeCoinResponse { | 20 | struct GradeCoinResponse { |
16 | res: ResponseType, | 21 | res: ResponseType, |
@@ -23,7 +28,9 @@ enum ResponseType { | |||
23 | Error, | 28 | Error, |
24 | } | 29 | } |
25 | 30 | ||
26 | use crate::schema::{AuthRequest, Block, Claims, Db, MetuId, NakedBlock, Transaction, User}; | 31 | use crate::schema::{ |
32 | AuthRequest, Block, Claims, Db, InitialAuthRequest, MetuId, NakedBlock, Transaction, User, | ||
33 | }; | ||
27 | 34 | ||
28 | const BEARER: &str = "Bearer "; | 35 | const BEARER: &str = "Bearer "; |
29 | 36 | ||
@@ -32,11 +39,34 @@ const BEARER: &str = "Bearer "; | |||
32 | /// Lets a [`User`] (=student) to authenticate themselves to the system | 39 | /// Lets a [`User`] (=student) to authenticate themselves to the system |
33 | /// This `request` can be rejected if the payload is malformed (= not authenticated properly) or if | 40 | /// This `request` can be rejected if the payload is malformed (= not authenticated properly) or if |
34 | /// the [`AuthRequest.user_id`] of the `request` is not in the list of users that can hold a Gradecoin account | 41 | /// the [`AuthRequest.user_id`] of the `request` is not in the list of users that can hold a Gradecoin account |
42 | /// The request first comes in encrypted | ||
35 | pub async fn authenticate_user( | 43 | pub async fn authenticate_user( |
36 | request: AuthRequest, | 44 | request: InitialAuthRequest, |
37 | db: Db, | 45 | db: Db, |
38 | ) -> Result<impl warp::Reply, warp::Rejection> { | 46 | ) -> Result<impl warp::Reply, warp::Rejection> { |
39 | debug!("POST request to /register, authenticate_user"); | 47 | debug!("POST request to /register, authenticate_user"); |
48 | |||
49 | // TODO: lazyload or something <14-04-21, yigit> // | ||
50 | let der_encoded = PRIVATE_KEY | ||
51 | .lines() | ||
52 | .filter(|line| !line.starts_with("-")) | ||
53 | .fold(String::new(), |mut data, line| { | ||
54 | data.push_str(&line); | ||
55 | data | ||
56 | }); | ||
57 | let der_bytes = base64::decode(&der_encoded).expect("failed to decode base64 content"); | ||
58 | let private_key = RSAPrivateKey::from_pkcs1(&der_bytes).expect("failed to parse key"); | ||
59 | |||
60 | let padding = PaddingScheme::new_oaep::<sha2::Sha256>(); | ||
61 | let dec_key = private_key | ||
62 | .decrypt(padding, &request.key.as_bytes()) | ||
63 | .expect("failed to decrypt"); | ||
64 | |||
65 | // then decrypt c using key dec_key | ||
66 | |||
67 | // let request: AuthRequest = serde_json::from_str(&String::from_utf8(dec_data).unwrap()).unwrap(); | ||
68 | let request; | ||
69 | |||
40 | let provided_id = request.student_id.clone(); | 70 | let provided_id = request.student_id.clone(); |
41 | 71 | ||
42 | let priv_student_id = match MetuId::new(request.student_id, request.passwd) { | 72 | let priv_student_id = match MetuId::new(request.student_id, request.passwd) { |
@@ -22,7 +22,45 @@ | |||
22 | //! `Authorization`: The request header should have Bearer JWT.Token signed with Student Public Key | 22 | //! `Authorization`: The request header should have Bearer JWT.Token signed with Student Public Key |
23 | 23 | ||
24 | pub mod custom_filters; | 24 | pub mod custom_filters; |
25 | pub mod error; | ||
25 | pub mod handlers; | 26 | pub mod handlers; |
26 | pub mod routes; | 27 | pub mod routes; |
27 | pub mod schema; | 28 | pub mod schema; |
28 | pub mod error; | 29 | |
30 | pub const PRIVATE_KEY: &'static str = "-----BEGIN RSA PRIVATE KEY----- | ||
31 | MIIEogIBAAKCAQEAyGuqiCPGcguy+Y9TH7Bl7XlEsalyqb9bYlzpbV0dnqZ3lPkE | ||
32 | PkuOhkN+GcuiV6iXtSwyh7nB+xTRXKJFRUBO/jbN8jfcxVwBu0JxjF3v1YRBxbOH | ||
33 | hz2A295mbKD9xHQCKxkfYBNkUXxj8gd+GaDvQiSW5NdrX/lEkvqfGtdEX1m2+Hdc | ||
34 | G0+3YW24Xg0znhCwLr+sorLuJaDy9Xa0Uo+DPWGC5s001U/BxkCIWJ+eJQCb7Bv+ | ||
35 | 9vXb8BGRK/ecMb/fb6h5O+8fgB64RCHMgcc2v+Q/dPt8kHX1OJdMuYUrUJGACppM | ||
36 | QY3W6e1HdlRIBcZKL2LMZ2CrIB/2D5LiJhPThQIDAQABAoIBABbHrg1lS5QA4mnd | ||
37 | MYyDh0JTq0wqP18t4dwvRVTp5Yj30NW87A+MlPmLyFR0QdKG1h+Ak4m7wmGgfx9x | ||
38 | TkBNy+y3G/dxBAXmrEe1iKR0tOLm8nbfLgNgKTpUb/3e2pkuumRdqaRI7/kXE2Ea | ||
39 | Guoc0bUJ5aDDH3A8K+As3lK1rw7LNxwxZdmqmpO+EAldP6NaLnXNP5BegjLK50xP | ||
40 | NXTDNx6pw+I2ZHHwC/A6+QVksSA6zPipI1poANaO0frHffwKhcEZ/VucuXlJGGq/ | ||
41 | aqXT/cc7IkKUVq8EZUwUqHi4SrnyDDq/mtuikSD0MazxumbeC6fBKRP98Kavy2rT | ||
42 | JItHSYECgYEA8H/yC9GDrR1bwBesD0pKdKBy18UMFQF3BrB04OjqdGzugdVafF4e | ||
43 | 7azYQQTQ0ZddLDvgYl0QYvQaZfv26L7o4VrN5XEg8WjUWKuww8XUYOCfPn4gOFL1 | ||
44 | ar8nQ0w3P65gYf/rw0rFMo3eB78rJMROYnG8nZ/3OdgQjVaYPJxFKmECgYEA1VZy | ||
45 | EQz8dHK3+F0EfQIFeXOSlYGUegmPZ9iYmh+yvW/zWKLYdXBEHNhAIRlBmfe7Yhj6 | ||
46 | 1FNluNGjFqZYuRnP0RuiBxt2RCd+AL90Lqq+O6jem4XNgr3cOKoaV0FbaU49sI4s | ||
47 | /B6iiYBFdVuPBiknz+Wf1KEF9lQ+w2VYSLucY6UCgYAWPe73ste3sehjWo0aGOfL | ||
48 | 427bj6ivZKRKZRVaG5BbVhu0vDOTHu1DU+HoGXbqe1ItnhgBYNP8ItEyL1xFaCqH | ||
49 | dOtn1c+TI/vHe5FseaZLk1qG4AlAzENQLP+HlMvjQtA9H/sA47BbHY20L7TgwJrz | ||
50 | NcuY1Et7+QSG3cRUjqtC4QKBgGuP+VUVehfwW0dzBrdMlJwGpGqS+dyKA271awOS | ||
51 | ZdlTn5saCA82OnFcqwDFLilGGYk9VQJGxivoLtVVq7gwBnLE/u2ccAWu773KyfZZ | ||
52 | ii6kVxCM5vA7b9R2F2/U+RTgKQRiutWnUIYJUXv5XORbTcJpYSugwFPRaA+2gkux | ||
53 | pAktAoGABRyVs5LOhQ/oeXe2H2kvuaUq9c7f/dTtnyMNdNxK0uZcQn4jcB2eK9kB | ||
54 | PDYHM9dfQ8xn51U0fTeaXjy/8Km8fyX2Jtxntlm6puyhSTJ8AX+FEgJkC4ajNEvA | ||
55 | mJ1Gsy2fXKUyyZdI2b74MLqOpzr9cvS60tmTIScuiHFzg/SJgiA= | ||
56 | -----END RSA PRIVATE KEY-----"; | ||
57 | |||
58 | pub const PUB_KEY: &'static str = "-----BEGIN PUBLIC KEY----- | ||
59 | MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyGuqiCPGcguy+Y9TH7Bl | ||
60 | 7XlEsalyqb9bYlzpbV0dnqZ3lPkEPkuOhkN+GcuiV6iXtSwyh7nB+xTRXKJFRUBO | ||
61 | /jbN8jfcxVwBu0JxjF3v1YRBxbOHhz2A295mbKD9xHQCKxkfYBNkUXxj8gd+GaDv | ||
62 | QiSW5NdrX/lEkvqfGtdEX1m2+HdcG0+3YW24Xg0znhCwLr+sorLuJaDy9Xa0Uo+D | ||
63 | PWGC5s001U/BxkCIWJ+eJQCb7Bv+9vXb8BGRK/ecMb/fb6h5O+8fgB64RCHMgcc2 | ||
64 | v+Q/dPt8kHX1OJdMuYUrUJGACppMQY3W6e1HdlRIBcZKL2LMZ2CrIB/2D5LiJhPT | ||
65 | hQIDAQAB | ||
66 | -----END PUBLIC KEY-----"; | ||
diff --git a/src/schema.rs b/src/schema.rs index 9e157c7..f159d83 100644 --- a/src/schema.rs +++ b/src/schema.rs | |||
@@ -178,7 +178,7 @@ pub struct MetuId { | |||
178 | passwd: String, | 178 | passwd: String, |
179 | } | 179 | } |
180 | 180 | ||
181 | // TODO: this will arrive encrypted <13-04-21, yigit> // | 181 | /// The plaintext of the initial user authentication request |
182 | #[derive(Serialize, Deserialize, Debug, PartialEq)] | 182 | #[derive(Serialize, Deserialize, Debug, PartialEq)] |
183 | pub struct AuthRequest { | 183 | pub struct AuthRequest { |
184 | pub student_id: String, | 184 | pub student_id: String, |
@@ -186,6 +186,13 @@ pub struct AuthRequest { | |||
186 | pub public_key: String, | 186 | pub public_key: String, |
187 | } | 187 | } |
188 | 188 | ||
189 | /// Ciphertext of the initial authentication request, or what we will receive | ||
190 | #[derive(Serialize, Deserialize, Debug)] | ||
191 | pub struct InitialAuthRequest { | ||
192 | pub c: String, | ||
193 | pub key: String, | ||
194 | } | ||
195 | |||
189 | lazy_static! { | 196 | lazy_static! { |
190 | static ref OUR_STUDENTS: HashSet<(&'static str, &'static str)> = { | 197 | static ref OUR_STUDENTS: HashSet<(&'static str, &'static str)> = { |
191 | [ | 198 | [ |