From: Konrad Rosenbaum Date: Mon, 2 Feb 2015 07:09:31 +0000 (+0100) Subject: initial src layout X-Git-Url: http://git.silmor.de/gitweb/?a=commitdiff_plain;p=web%2Fkonrad%2Fu2f-demo.git initial src layout --- acada2e15eac439dd6d12a10c5ab649f0937ea96 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..7643b02 --- /dev/null +++ b/.gitignore @@ -0,0 +1,10 @@ +/u2f-client-demo* +/u2f-server-demo* +moc_* +*.o +*.obj +*.bak +*~ +Makefile* +*.kdev4 +.kdev* diff --git a/COPYING.MIT b/COPYING.MIT new file mode 100644 index 0000000..bca296b --- /dev/null +++ b/COPYING.MIT @@ -0,0 +1,19 @@ +Copyright (c) 2014 Konrad Rosenbaum + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. \ No newline at end of file diff --git a/README b/README new file mode 100644 index 0000000..263f127 --- /dev/null +++ b/README @@ -0,0 +1,55 @@ +README for U2F Demo +==================== + +(c) Konrad Rosenbaum , 2015 +this demo is protected under the MIT license, see COPYING.MIT for details + + +This is some demo code to show how to integrate FIDO U2F into your own code. +Apart from this it does not have a useful purpose. + + +Pre-Requisites and Building +---------------------------- + +You need for the Qt based client/server: +* GIT to retrieve the U2F libs +* PKG-Config +* a working C/C++ compiler (e.g. gcc, clang) +* libu2f-host (https://github.com/Yubico/libu2f-host.git), which itself + requires: + - GNU autotools + - GTK-doc (optional for building documentation) + - HIDAPI (use HIDAPI-hidraw under Linux!) +* libu2f-server (https://github.com/Yubico/libu2f-server.git), which itsel + requires: + - GNU autotools + - GTK-doc (optional for building documentation) + - OpenSSL (for cryptography) +* Qt (>=5.3) for the graphical server and client demo + +For the PHP based server demo: +* PHP >= 5.x + - with the OpenSSL extension enabled (the web server does not need to use HTTPS) + +Compile and install libu2f-host and libu2f-server first - see the README files +of those libraries for details. + +Call "qmake && make" in the main directory - normally it should work out of the +box as long as qmake is in the $PATH. If pkg-config cannot find the two libu2f +libraries, then you may have to set the PKG_CONFIG_PATH variable to point to +the directory where the *.pc files for libu2f-* are installed (per default +/usr/local/lib/pkgconfig - if you set another --prefix before installing them +it is $PREFIX/lib/pkgconfig). + +The PHP demo does not need to be built: just copy the directory to a path that can +be served by a PHP-enabled web server. + +Using the Demo Server and Client +--------------------------------- + + +Using the Web Demo +------------------- + +TBD \ No newline at end of file diff --git a/client/client.pro b/client/client.pro new file mode 100644 index 0000000..a9e9cb3 --- /dev/null +++ b/client/client.pro @@ -0,0 +1,15 @@ +#U2F Demo Client + +# make it a normal GUI app, so we can interact +TEMPLATE = app +TARGET = u2f-client-demo +DESTDIR = .. +QT += widgets network + +# make sure u2f-host lib is linked - needed for USB-to-token-access +CONFIG += link_pkgconfig +PKGCONFIG += u2f-host + +# source files... +SOURCES += clientmain.cpp + diff --git a/client/clientmain.cpp b/client/clientmain.cpp new file mode 100644 index 0000000..5119b5a --- /dev/null +++ b/client/clientmain.cpp @@ -0,0 +1,11 @@ +#include +#include + + +int main(int ac,char**av) +{ + QApplication app(ac,av); + QPushButton p("hello"); + p.show(); + return app.exec(); +} \ No newline at end of file diff --git a/client/democonsts.h b/client/democonsts.h new file mode 100644 index 0000000..bb0b6ee --- /dev/null +++ b/client/democonsts.h @@ -0,0 +1,10 @@ +#ifndef U2F_QT_DEMO_CONSTANTS_H +#define U2F_QT_DEMO_CONSTANTS_H + +//network TCP port to be used for the demo protocol +#define DEMOPORT 29682 + +//URI scheme for the demo protocol +#define DEMOSCHEME "demo" + +#endif \ No newline at end of file diff --git a/server/connection.cpp b/server/connection.cpp new file mode 100644 index 0000000..4985d87 --- /dev/null +++ b/server/connection.cpp @@ -0,0 +1,21 @@ +#include "connection.h" + +#include + +DConnection::DConnection(QTcpSocket*sock, QObject* parent): QObject(parent), msocket(sock) +{ +} + +DConnection::State DConnection::state() const +{ + //unconnected? + if(msocket==nullptr || !msocket->isOpen()) + return Invalid; + //we are connected, check details + //are we authenticating? + if(mkeys.size()>0)return Authenticating; + //done authenticating? + if(!muser.isEmpty())return Authenticated; + //not authenticated yet + return Connected; +} diff --git a/server/connection.h b/server/connection.h new file mode 100644 index 0000000..805da56 --- /dev/null +++ b/server/connection.h @@ -0,0 +1,38 @@ +#ifndef DEMO_CONNECTION_H +#define DEMO_CONNECTION_H + + +#include +#include + +class QTcpSocket; + +class DConnection:public QObject +{ + Q_OBJECT +public: + explicit DConnection(QTcpSocket*,QObject* parent = 0); + + ///Represents the current state of this connection. + enum State { + ///The connection is invalid or disconnected. + Invalid, + ///It is connected, but not authenticated. + Connected, + ///It is currently authenticating the user. + ///When finished it will either revert to Connected (failed) + ///or advance to Authenticated (success). + Authenticating, + ///Authentication was successful. The user may request data + ///or change his/her token associations. + Authenticated, + }; + State state()const; + QString userName()const{return muser;} +private: + QTcpSocket*msocket; + QString muser; + QStringList mkeys; +}; + +#endif diff --git a/server/server.pro b/server/server.pro new file mode 100644 index 0000000..5820ed6 --- /dev/null +++ b/server/server.pro @@ -0,0 +1,19 @@ +#U2F Demo Server + +# make it a normal GUI app, so we can see what is happening +TEMPLATE = app +TARGET = u2f-server-demo +DESTDIR = .. +QT += widgets network + +# allow C++11 keywords +CONFIG += c++11 + +# make sure the u2f-server lib is linked: needed for the crypto +CONFIG += link_pkgconfig +PKGCONFIG += u2f-server + +# source files +SOURCES += servermain.cpp session.cpp connection.cpp +HEADERS += servermain.h session.h connection.h + diff --git a/server/servermain.cpp b/server/servermain.cpp new file mode 100644 index 0000000..59793c7 --- /dev/null +++ b/server/servermain.cpp @@ -0,0 +1,52 @@ +#include "servermain.h" +#include "session.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +void DMainWindow::choseHost() +{ + QStringList hosts; + hosts<<"localhost"<quit(); + return; + } + DSession*sess; + if(host==hosts[0]) + sess=DSession::createLocalSession(); + else + sess=DSession::createDefaultSession(); + minstance=new DMainWindow(sess); + minstance->show(); +} + +QPointer DMainWindow::minstance; + +DMainWindow::DMainWindow(DSession*s) + :msession(s) +{ + setWindowTitle("Demo Server: "+s->hostname()); + statusBar()->setSizeGripEnabled(true); + + QMenu*m=menuBar()->addMenu("Session"); + m->addAction("Quit",qApp,SLOT(quit())); +} + + + +int main(int ac,char**av) +{ + QApplication app(ac,av); + DMainWindow::choseHost(); + return app.exec(); +} \ No newline at end of file diff --git a/server/servermain.h b/server/servermain.h new file mode 100644 index 0000000..628f262 --- /dev/null +++ b/server/servermain.h @@ -0,0 +1,23 @@ +#ifndef DEMO_SERVERMAIN_H +#define DEMO_SERVERMAIN_H + +#include +#include + +class DSession; + +class DMainWindow:public QMainWindow +{ + Q_OBJECT +public: + static void choseHost(); + static DMainWindow* instance(){return minstance;} +private: + DMainWindow(DSession*); + + static QPointerminstance; + QPointermsession; +}; + + +#endif diff --git a/server/session.cpp b/server/session.cpp new file mode 100644 index 0000000..d38fcbd --- /dev/null +++ b/server/session.cpp @@ -0,0 +1,51 @@ +#include "session.h" + +#include +#include +#include + +#include "connection.h" +#include "../client/democonsts.h" + +DSession::DSession(QHostAddress addr, QString host): QObject(), mhost(host) +{ + mserver=new QTcpServer(this); + mserver->listen(addr,DEMOPORT); + connect(mserver,SIGNAL(newConnection()),this,SLOT(handleConnect())); +} + +bool DSession::isValid() const +{ + return mserver!=nullptr && mserver->isListening(); +} + +QString DSession::url() const +{ + if(isValid()) + return QString(DEMOSCHEME "://%1").arg(mhost); + else + return QString(); +} + + +void DSession::handleConnect() +{ + while(mserver->hasPendingConnections()){ + QTcpSocket*sock=mserver->nextPendingConnection(); + if(sock) + emit newConnection(new DConnection(sock)); + } +} + +DSession* DSession::createLocalSession() +{ + return new DSession(QHostAddress::LocalHost, "localhost"); +} + +DSession* DSession::createDefaultSession() +{ + QString host=QHostInfo::localHostName(); + if(!host.contains('.')) + host+="."+QHostInfo::localDomainName(); + return new DSession(QHostAddress::Any, host); +} diff --git a/server/session.h b/server/session.h new file mode 100644 index 0000000..502ea42 --- /dev/null +++ b/server/session.h @@ -0,0 +1,51 @@ +#ifndef DEMO_SESSION_H +#define DEMO_SESSION_H + +#include +#include +#include + +class QTcpServer; +class QTcpSocket; +class DConnection; + + +///This class represents the server session. +///The server session holds all important data and main objects together: +/// the server socket, URL, data directory, etc. +class DSession:public QObject +{ + Q_OBJECT +public: + ///returns true if the session was correctly constructed + bool isValid()const; + + ///returns the host name of the session + QString hostname()const{return mhost;} + ///returns the URL the client needs + QString url()const; + + /// Creates a session for localhost + static DSession* createLocalSession(); + /// Creates a session for the default hostname + static DSession* createDefaultSession(); + +signals: + ///emitted when a new connection is established + void newConnection(DConnection*); + +private slots: + ///handles TCP connections + void handleConnect(); + +private: + ///creates a new session, called by create*Session() + DSession(QHostAddress addr, QString host); + + + QTcpServer*mserver; + QString mhost; +}; + + +#endif diff --git a/u2f-demo.pro b/u2f-demo.pro new file mode 100644 index 0000000..f3cf3d8 --- /dev/null +++ b/u2f-demo.pro @@ -0,0 +1,2 @@ +TEMPLATE=subdirs +SUBDIRS = server client