Commit 4648cdb3 authored by Robert Czechowski's avatar Robert Czechowski
Browse files

Generalise OAuth login – Part I: Read config and show login links

parent a13db7e8
......@@ -51,8 +51,10 @@ type MedalValue = (String, json_val::Map<String, json_val::Value>);
type MedalResult<T> = Result<T, MedalError>;
type MedalValueResult = MedalResult<MedalValue>;
use oauth_provider::OauthProvider;
pub fn index<T: MedalConnection>(conn: &T, session_token: Option<String>,
(self_url, oauth_url): (Option<String>, Option<String>))
(self_url, oauth_providers): (Option<String>, Option<Vec<OauthProvider>>))
-> (String, json_val::Map<String, json_val::Value>)
{
let mut data = json_val::Map::new();
......@@ -69,8 +71,19 @@ pub fn index<T: MedalConnection>(conn: &T, session_token: Option<String>,
}
}
let mut oauth_links : Vec<(String, String, String)> = Vec::new();
if let Some(oauth_providers) = oauth_providers {
println!("tblub");
for oauth_provider in oauth_providers {
oauth_links.push((oauth_provider.provider_id.to_owned(),
oauth_provider.login_link_text.to_owned(),
oauth_provider.url.to_owned()));
println!("testayy {}", oauth_provider.provider_id.to_owned());
}
}
data.insert("self_url".to_string(), to_json(&self_url));
data.insert("oauth_url".to_string(), to_json(&oauth_url));
data.insert("oauth_links".to_string(), to_json(&oauth_links));
/*contests.push("blaa".to_string());
data.insert("contest".to_string(), to_json(&contests));*/
......
......@@ -47,16 +47,14 @@ use std::path;
use std::path::{Path, PathBuf};
use structopt::StructOpt;
#[derive(Serialize, Deserialize, Clone, Default)]
mod oauth_provider;
#[derive(Serialize, Deserialize, Clone, Default, Debug)]
pub struct Config {
host: Option<String>,
port: Option<u16>,
self_url: Option<String>,
oauth_url: Option<String>,
oauth_client_id: Option<String>,
oauth_client_secret: Option<String>,
oauth_access_token_url: Option<String>,
oauth_user_data_url: Option<String>,
oauth_providers: Option<Vec<oauth_provider::OauthProvider>>,
database_file: Option<PathBuf>,
}
......@@ -74,6 +72,13 @@ fn read_config_from_file(file: &Path) -> Config {
Default::default()
};
if let Some(ref oap) = config.oauth_providers {
println!("OAuth providers:");
for oap in oap {
println!(" * {}", oap.provider_id);
}
}
if config.host.is_none() {
config.host = Some("[::]".to_string())
}
......@@ -185,10 +190,10 @@ fn add_admin_user(conn: &mut Connection, resetpw: bool) {
admin.username = Some("admin".into());
match admin.set_password(&password) {
None => println!("FAILED! (Password hashing error)"),
None => println!(" FAILED! (Password hashing error)"),
_ => {
conn.save_session(admin);
println!("Done");
println!(" Done");
}
}
}
......
#[derive(Serialize, Deserialize, Clone, Default, Debug)]
pub struct OauthProvider {
pub provider_id: String,
pub url: String,
pub client_id: String,
pub client_secret: String,
pub access_token_url: String,
pub user_data_url: String,
pub login_link_text: String,
}
......@@ -156,6 +156,7 @@ trait RequestRouterParam {
fn get_str(self: &mut Self, key: &str) -> Option<String>;
fn get_int<T: ::std::str::FromStr>(self: &mut Self, key: &str) -> Option<T>;
fn expect_int<T: ::std::str::FromStr>(self: &mut Self, key: &str) -> IronResult<T>;
fn expect_str(self: &mut Self, key: &str) -> IronResult<String>;
}
impl<'a, 'b> RequestRouterParam for Request<'a, 'b> {
......@@ -175,6 +176,15 @@ impl<'a, 'b> RequestRouterParam for Request<'a, 'b> {
response: Response::with(status::Forbidden) }),
}
}
fn expect_str(self: &mut Self, key: &str) -> IronResult<String> {
match self.get_str(key) {
Some(s) => Ok(s),
_ => Err(IronError { error: Box::new(SessionError { message:
"Routing parameter missing".to_string() }),
response: Response::with(status::Forbidden) }),
}
}
}
use functions;
......@@ -232,10 +242,10 @@ fn greet_personal(req: &mut Request) -> IronResult<Response> {
let session_token = req.get_session_token();
// hier ggf. Daten aus dem Request holen
let (self_url, oauth_url) = {
let (self_url, oauth_providers) = {
let mutex = req.get::<Write<SharedConfiguration>>().unwrap();
let config = mutex.lock().unwrap_or_else(|e| e.into_inner());
(config.self_url.clone(), config.oauth_url.clone())
(config.self_url.clone(), config.oauth_providers.clone())
};
let (template, data) = {
......@@ -244,7 +254,7 @@ fn greet_personal(req: &mut Request) -> IronResult<Response> {
let conn = mutex.lock().unwrap_or_else(|e| e.into_inner());
// Antwort erstellen und zurücksenden
functions::index(&*conn, session_token, (self_url, oauth_url))
functions::index(&*conn, session_token, (self_url, oauth_providers))
};
// Daten verarbeiten
......@@ -300,16 +310,17 @@ fn contest_post(req: &mut Request) -> IronResult<Response> {
}
fn login(req: &mut Request) -> IronResult<Response> {
let (self_url, oauth_url) = {
let (self_url, oauth_providers) = {
let mutex = req.get::<Write<SharedConfiguration>>().unwrap();
let config = mutex.lock().unwrap_or_else(|e| e.into_inner());
(config.self_url.clone(), config.oauth_url.clone())
(config.self_url.clone(), config.oauth_providers.clone())
};
let mut data = json_val::Map::new();
data.insert("self_url".to_string(), to_json(&self_url));
data.insert("oauth_url".to_string(), to_json(&oauth_url));
// TODO: Generate list of links as in greet_personal
// data.insert("oauth_url".to_string(), to_json(&oauth_url));
let mut resp = Response::new();
resp.set_mut(Template::new("login", data)).set_mut(status::Ok);
......@@ -589,15 +600,31 @@ fn oauth(req: &mut Request) -> IronResult<Response> {
use params::{Params, Value};
use reqwest::header;
let oauth_id = req.expect_str("oauthid")?;
let (client_id, client_secret, access_token_url, user_data_url) = {
let mutex = req.get::<Write<SharedConfiguration>>().unwrap();
let config = mutex.lock().unwrap_or_else(|e| e.into_inner());
if let (Some(id), Some(secret), Some(atu), Some(udu)) = (&config.oauth_client_id,
&config.oauth_client_secret,
&config.oauth_access_token_url,
&config.oauth_user_data_url)
{
(id.clone(), secret.clone(), atu.clone(), udu.clone())
let mut result: Option<(String, String, String, String)> = None;
if let Some(ref oauth_providers) = config.oauth_providers {
for oauth_provider in oauth_providers {
if oauth_provider.provider_id == oauth_id {
result = Some(
(oauth_provider.client_id.clone(),
oauth_provider.client_secret.clone(),
oauth_provider.access_token_url.clone(),
oauth_provider.user_data_url.clone()));
break;
}
}
if let Some(result) = result {
result
} else {
return Ok(Response::with(iron::status::NotFound));
}
} else {
return Ok(Response::with(iron::status::NotFound));
}
......@@ -766,10 +793,11 @@ pub fn start_server(conn: Connection, config: ::Config) -> iron::error::HttpResu
user: get "/user/:userid" => user,
user_post: post "/user/:userid" => user_post,
task: get "/task/:taskid" => task,
oauth: get "/oauth" => oauth,
oauth: get "/oauth/:oauthid" => oauth,
check_cookie: get "/cookie" => cookie_warning,
);
// TODO: how important is this? Should this be in the config?
let my_secret = b"verysecret".to_vec();
let mut mount = Mount::new();
......
......@@ -25,11 +25,11 @@
<input type="text" name="code" value="{{ code }}" size="8">
<input type="submit" value="log in">
</form>
{{#if oauth_url}}
{{#if self_url}}
<a href="{{ oauth_url }}{{ self_url }}/oauth">PMS-Login für Lehrer</a>
{{/if}}
{{#if self_url}}
{{#each oauth_links}}
<a href="{{ this.2 }}{{ self_url }}/oauth/{{ this.0 }}">{{ this.1 }}</a>
{{/each}}
{{/if}}
{{/if}}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment