Commit 644c4ca3 by Czémán Arnold

Add SAML2 ECP login method

parent 617b2288
......@@ -2,11 +2,11 @@ CPP=g++
CC=gcc
AR=ar
CFLAGS=-fPIC -Ofast
CPPFLAGS=-fPIC --std=c++11 -Ofast -Irestclient-cpp/include
CPPFLAGS=-fPIC --std=c++11 -Ofast -Irestclient-cpp/include `pkg-config --cflags lasso`
LDFLAGS=--shared
LIBS=-lrestclient-cpp -lcurl
LIBS=-lrestclient-cpp -lcurl `pkg-config --libs lasso` -lgobject-2.0 -lgumbo -lgq
SONAME=_occi.so
SOURCES=compute.cpp entity.cpp network.cpp occisession.cpp resource.cpp storage.cpp template.cpp link.cpp
SOURCES=compute.cpp entity.cpp network.cpp occisession.cpp resource.cpp storage.cpp template.cpp link.cpp saml2_ecp.cpp
SWIG=swig
SWIG_INTERFACES=occilib.i
......
......@@ -23,6 +23,7 @@
#include "json.hpp"
#include "occisession.h"
#include "saml2_ecp.h"
#include <gq/Document.h>
#include <gq/Node.h>
......@@ -143,6 +144,20 @@ void OcciSession::BMELogin(string username, string password, bool insecure){
this->connection->setCookies(r.cookies);
}
void OcciSession::saml2EcpLogin(std::string username,
std::string password,
std::string metadata,
bool insecure){
auto r = saml2_ecp_login(username, password,
url + "/saml2/login/",
metadata,
insecure);
this->connection->setCookies(r.cookies);
}
json OcciSession::queryInterface(){
return get("-/");
}
......@@ -60,6 +60,10 @@ namespace OcciClient {
void circleOcciLogin(std::string username, std::string password);
void BMELogin(std::string username, std::string password, bool insecure=false);
void saml2EcpLogin(std::string username,
std::string password,
std::string metadata,
bool insecure=false);
nlohmann::json queryInterface();
};
......
......@@ -8,5 +8,10 @@ namespace OcciClient{
OcciSession(const char* url, bool insecure = false, bool csrf = false);
~OcciSession();
void circleOcciLogin(std::string username, std::string password);
void BMELogin(std::string username, std::string password, bool insecure=false);
void saml2EcpLogin(std::string username,
std::string password,
std::string metadata,
bool insecure=false);
};
}
#include "saml2_ecp.h"
#include <restclient-cpp/connection.h>
#include <lasso/lasso.h>
#include <lasso/xml/soap-1.1/xml_soap11.h>
#include <iostream>
#include <fstream>
#include <string>
using namespace RestClient;
namespace OcciClient{
static inline void check_error(int error_code){
if(error_code < 0)
throw std::runtime_error(lasso_strerror(error_code));
}
static inline void check_http_error(Response resp){
if(resp.code < 400) return;
LassoSoapFault* fault = lasso_soap_fault_new_from_message(resp.body.c_str());
const char* message = fault->faultstring;
if(message == NULL) message = resp.body.c_str();
throw HttpError(message, resp.code);
}
// SAML2 Profile for ECP (Section 4.2) defines these steps for an ECP
// transaction
//
// 1. ECP issues HTTP Request to SP
// 2. SP issues <AuthnRequest> to ECP using PAOS
// 3. ECP determines IdP
// 4. ECP conveys <AuthnRequest> to IdP using SOAP
// 5. IdP identifies principal
// 6. IdP issues <Response> to ECP, targeted at SP using SOAP
// 7. ECP conveys <Response> to SP using PAOS
// 8. SP grants or denies access to principal
RestClient::Response saml2_ecp_login(std::string username,
std::string password,
std::string login_url,
std::string metadata,
bool insecure){
lasso_init();
auto con = Connection("");
Response r;
if (insecure) {
con.SetHostVerify(false);
con.SetPeerVerify(false);
}
// init ECP session
LassoServer* ecpContext = lasso_server_new(NULL, NULL, NULL, NULL);
if(ecpContext == NULL)
throw std::runtime_error("Cannot create ECP client (ecpContext)");
lasso_provider_set_protocol_conformance(LASSO_PROVIDER(ecpContext),
LASSO_PROTOCOL_SAML_2_0);
check_error(lasso_server_add_provider(ecpContext, LASSO_PROVIDER_ROLE_IDP,
metadata.c_str(), NULL, NULL));
LassoEcp* ecp = lasso_ecp_new(ecpContext);
if(ecp == NULL)
throw std::runtime_error("Cannot create ECP client (ecp)");
try{
// phase 1.
HeaderFields headers;
headers["Accept"] = MEDIA_TYPE_PAOS;
headers["PAOS"] = PAOS_HEADER;
con.SetHeaders(headers);
r = con.get(login_url);
check_http_error(r);
// phase 2-6.
check_error(lasso_ecp_process_authn_request_msg(ecp, r.body.c_str()));
con.SetBasicAuth(username, password);
headers["Content-Type"] = MEDIA_TYPE_SOAP;
con.SetHeaders(headers);
LassoProfile* profile = LASSO_PROFILE(ecp);
r = con.post(profile->msg_url, profile->msg_body);
check_http_error(r);
// phase 7-8.
check_error(lasso_ecp_process_response_msg(ecp, r.body.c_str()));
headers = HeaderFields();
headers["Content-Type"] = MEDIA_TYPE_PAOS;
con.SetHeaders(headers);
r = con.post(profile->msg_url, profile->msg_body);
check_http_error(r);
}
catch(std::exception&){
// destroy session
lasso_server_destroy(ecpContext);
lasso_ecp_destroy(ecp);
lasso_shutdown();
throw;
}
// destroy session
lasso_server_destroy(ecpContext);
lasso_ecp_destroy(ecp);
lasso_shutdown();
return r;
}
}
#ifndef SAML2_ECP_H
#define SAML2_ECP_H
#include <restclient-cpp/restclient.h>
#include <stdexcept>
#define MEDIA_TYPE_PAOS "application/vnd.paos+xml"
#define PAOS_HEADER ("ver=\"" LASSO_PAOS_HREF "\";\"" LASSO_ECP_HREF "\"")
#define MEDIA_TYPE_SOAP "application/soap+xml"
namespace OcciClient {
struct HttpError: public std::runtime_error{
int status_code;
std::string message;
HttpError(std::string message, int status_code)
:runtime_error(""),status_code(status_code){
this->message = std::string("Status code: ") +
std::to_string(status_code) +
" Message: " + message;
}
const char* what() const noexcept{
return message.c_str();
}
};
RestClient::Response saml2_ecp_login(std::string username,
std::string password,
std::string login_url,
std::string metadata,
bool insecure=false);
}
#endif // SAML2_ECP_H
......@@ -17,7 +17,13 @@ _occi = Extension('_occi',
library_dirs=['.'],
swig_opts=['-c++'],
extra_compile_args=['-std=c++11', '-Ofast'],
libraries=['occi', 'restclient-cpp', 'curl']
libraries=['occi', 'restclient-cpp', 'curl',
# for BMElogin method
'gq', 'gumbo',
# for saml2EcpLogin method
'lasso', 'xmlsec1', 'gobject-2.0', 'ffi',
'xslt', 'dl', 'xml2', 'z', 'm', 'glib-2.0',
]
)
......@@ -27,6 +33,7 @@ class Build(build_ext):
check_call(['make', 'lib'])
build_ext.run(self)
setup(
name='libocci',
......
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 sign in to comment