api2/access.rs: add ticket api

This commit is contained in:
Dietmar Maurer 2019-01-30 15:14:20 +01:00
parent 1bf446a33e
commit 34f956bc25
8 changed files with 262 additions and 11 deletions

View File

@ -10,6 +10,7 @@ pub mod admin;
pub mod node;
mod version;
mod subscription;
mod access;
use lazy_static::lazy_static;
use crate::tools::common_regex;
@ -79,13 +80,15 @@ pub fn router() -> Router {
let route = Router::new()
.get(ApiMethod::new(
|_,_,_| Ok(json!([
{"subdir": "config"},
{"subdir": "access"},
{"subdir": "admin"},
{"subdir": "config"},
{"subdir": "nodes"},
{"subdir": "subscription"},
{"subdir": "version"},
])),
ObjectSchema::new("Directory index.")))
.subdir("access", access::router())
.subdir("admin", admin::router())
.subdir("config", config::router())
.subdir("nodes", nodes)

86
src/api2/access.rs Normal file
View File

@ -0,0 +1,86 @@
use failure::*;
use crate::tools;
use crate::api::schema::*;
use crate::api::router::*;
use crate::tools::ticket::*;
use crate::auth_helpers::*;
use serde_json::{json, Value};
fn authenticate_user(username: &str, password: &str) -> Result<(), Error> {
if username == "root@pam" && password == "test" {
return Ok(());
}
bail!("inavlid credentials");
}
fn create_ticket(
param: Value,
_info: &ApiMethod,
rpcenv: &mut RpcEnvironment,
) -> Result<Value, Error> {
let username = tools::required_string_param(&param, "username")?;
let password = tools::required_string_param(&param, "password")?;
match authenticate_user(username, password) {
Ok(_) => {
let ticket = assemble_rsa_ticket( private_auth_key(), "PBS", None, None)?;
let token = assemble_csrf_prevention_token(csrf_secret(), username);
log::info!("successful auth for user '{}'", username);
return Ok(json!({
"username": username,
"ticket": ticket,
"CSRFPreventionToken": token,
}));
}
Err(err) => {
let client_ip = "unknown"; // $rpcenv->get_client_ip() || '';
log::error!("authentication failure; rhost={} user={} msg={}", client_ip, username, err.to_string());
bail!("authentication failure");
}
}
}
pub fn router() -> Router {
let route = Router::new()
.get(ApiMethod::new(
|_,_,_| Ok(json!([
{"subdir": "ticket"}
])),
ObjectSchema::new("Directory index.")))
.subdir(
"ticket",
Router::new()
.post(
ApiMethod::new(
create_ticket,
ObjectSchema::new("Create or verify authentication ticket.")
.required(
"username",
StringSchema::new("User name.")
.max_length(64)
)
.required(
"password",
StringSchema::new("The secret password. This can also be a valid ticket.")
)
).returns(
ObjectSchema::new("Returns authentication ticket with additional infos.")
.required("username", StringSchema::new("User name."))
.required("ticket", StringSchema::new("Auth ticket."))
.required("CSRFPreventionToken", StringSchema::new("Cross Site Request Forgery Prevention Token."))
).protected(true)
)
);
route
}

View File

@ -247,8 +247,8 @@ fn handle_async_api_request(
fn get_index() -> BoxFut {
let nodename = tools::nodename();
let username = "fakelogin"; // todo: implement real auth
let token = "abc";
let username = ""; // fixme: implement real auth
let token = "";
let setup = json!({
"Setup": { "auth_cookie_name": "PBSAuthCookie" },

View File

@ -20,15 +20,30 @@ Ext.define('PBS.Application', {
logout: function() {
var me = this;
//Proxmox.Utils.authClear();
//me.changeView('loginview', true);
Proxmox.Utils.authClear();
me.changeView('loginview', true);
},
changeView: function(view, skipCheck) {
var me = this;
//?
PBS.view = view;
me.view = view;
if (me.currentView != undefined) {
me.currentView.destroy();
}
me.currentView = Ext.create({
xtype: view,
});
if (skipCheck !== true) {
// fixme:
// Proxmox.Utils.checked_command(function() {}); // display subscription status
}
},
view: 'loginview',
launch: function() {
var me = this;
Ext.on('resize', me.realignWindows);
@ -36,11 +51,13 @@ Ext.define('PBS.Application', {
var provider = new Ext.state.LocalStorageProvider({ prefix: 'ext-pbs-' });
Ext.state.Manager.setProvider(provider);
// fixme: show login window if not loggedin
me.currentView = Ext.create({
xtype: 'mainview'
});
// show login window if not loggedin
var loggedin = Proxmox.Utils.authOK();
if (!loggedin) {
me.changeView('loginview', true);
} else {
me.changeView('mainview', true);
}
}
});

128
www/LoginView.js Normal file
View File

@ -0,0 +1,128 @@
Ext.define('PBS.LoginView', {
extend: 'Ext.container.Container',
xtype: 'loginview',
controller: {
xclass: 'Ext.app.ViewController',
submitForm: function() {
var me = this;
var view = me.getView();
var loginForm = me.lookupReference('loginForm');
if (loginForm.isValid()) {
if (loginForm.isVisible()) {
loginForm.mask(gettext('Please wait...'), 'x-mask-loading');
}
loginForm.submit({
success: function(form, action) {
// save login data and create cookie
PBS.Utils.updateLoginData(action.result.data);
PBS.app.changeView('mainview');
},
failure: function(form, action) {
loginForm.unmask();
Ext.MessageBox.alert(
gettext('Error'),
gettext('Login failed. Please try again')
);
}
});
}
},
control: {
'button[reference=loginButton]': {
click: 'submitForm'
}
}
},
plugins: 'viewport',
layout: {
type: 'border'
},
items: [
{
region: 'north',
xtype: 'container',
layout: {
type: 'hbox',
align: 'middle'
},
margin: '2 5 2 5',
height: 38,
items: [
{
xtype: 'proxmoxlogo'
},
{
xtype: 'versioninfo',
makeApiCall: false
}
]
},
{
region: 'center'
},
{
xtype: 'window',
closable: false,
resizable: false,
reference: 'loginwindow',
autoShow: true,
modal: true,
defaultFocus: 'usernameField',
layout: {
type: 'auto'
},
title: gettext('Proxmox Backup Server Login'),
items: [
{
xtype: 'form',
layout: {
type: 'form'
},
defaultButton: 'loginButton',
url: '/api2/extjs/access/ticket',
reference: 'loginForm',
fieldDefaults: {
labelAlign: 'right',
allowBlank: false
},
items: [
{
xtype: 'textfield',
fieldLabel: gettext('User name'),
name: 'username',
itemId: 'usernameField',
reference: 'usernameField'
},
{
xtype: 'textfield',
inputType: 'password',
fieldLabel: gettext('Password'),
name: 'password',
reference: 'passwordField'
}
],
buttons: [
{
text: gettext('Login'),
reference: 'loginButton',
formBind: true
}
]
}
]
}
]
});

View File

@ -82,10 +82,20 @@ Ext.define('PBS.MainView', {
},
logout: function() {
PBS.app.logout();
},
navigate: function(treelist, item) {
this.redirectTo(item.get('path'));
},
control: {
'button[reference=logoutButton]': {
click: 'logout'
}
},
init: function(view) {
var me = this;
console.log("init");

View File

@ -1,6 +1,7 @@
JSSRC= \
Utils.js \
Logo.js \
LoginView.js \
VersionInfo.js \
SystemConfiguration.js \
Subscription.js \

View File

@ -6,6 +6,12 @@ console.log("Starting Backup Server GUI");
Ext.define('PBS.Utils', {
singleton: true,
updateLoginData: function(data) {
Proxmox.CSRFPreventionToken = data.CSRFPreventionToken;
Proxmox.UserName = data.username;
Ext.util.Cookies.set('PBSAuthCookie', data.ticket, null, '/', null, true );
},
constructor: function() {
var me = this;