mirror of
https://github.com/tomahawk-player/tomahawk.git
synced 2025-04-20 07:52:30 +02:00
Basic skeleton for api authentication
This commit is contained in:
parent
1bae47da51
commit
4cdfd81fb5
@ -112,6 +112,9 @@ IF( QXTWEB_FOUND )
|
||||
web/Api_v2.cpp
|
||||
web/Api_v2_0.cpp
|
||||
web/Api2HttpsServerConnector.cpp
|
||||
web/Api2User.cpp
|
||||
web/apiv2/ACLItemDelegate.cpp
|
||||
web/apiv2/ACLJobStatusItem.cpp
|
||||
)
|
||||
LIST(APPEND LINK_LIBRARIES ${QXTWEB_LIBRARIES})
|
||||
INCLUDE_DIRECTORIES(${QXTWEB_INCLUDE_DIRS})
|
||||
|
@ -19,11 +19,15 @@
|
||||
#include "Api_v2_0.h"
|
||||
|
||||
#include "audio/AudioEngine.h"
|
||||
#include "jobview/JobStatusModel.h"
|
||||
#include "jobview/JobStatusView.h"
|
||||
#include "utils/Logger.h"
|
||||
#include "web/apiv2/ACLJobStatusItem.h"
|
||||
|
||||
#include "Api_v2.h"
|
||||
#include "Query.h"
|
||||
|
||||
#include <QSslKey>
|
||||
#include <QxtWeb/QxtWebPageEvent>
|
||||
#include <QxtWeb/QxtWebSlotService>
|
||||
|
||||
@ -90,6 +94,47 @@ Api_v2_0::playback( QxtWebRequestEvent* event, const QString& command )
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Api_v2_0::requestauth( QxtWebRequestEvent *event )
|
||||
{
|
||||
tLog() << Q_FUNC_INFO;
|
||||
if ( checkAuthentication( event ) )
|
||||
{
|
||||
// A decision was already made.
|
||||
m_service->sendJsonOk( event );
|
||||
return;
|
||||
}
|
||||
|
||||
if ( event->isSecure && !event->clientCertificate.isNull() )
|
||||
{
|
||||
tLog() << Q_FUNC_INFO;
|
||||
QSslCertificate certificate = event->clientCertificate;
|
||||
QString clientName = certificate.subjectInfo( QSslCertificate::CommonName );
|
||||
|
||||
if ( m_users.contains( clientName ) && m_users.value( clientName )->aclDecision() == Api2User::Deny )
|
||||
{
|
||||
// Access was already denied
|
||||
jsonUnauthenticated( event );
|
||||
return;
|
||||
}
|
||||
|
||||
QSharedPointer<Api2User> user( new Api2User( clientName ) );
|
||||
user->setClientDescription( certificate.subjectInfo( QSslCertificate::OrganizationalUnitName ) );
|
||||
user->setClientName( certificate.subjectInfo( QSslCertificate::Organization ) );
|
||||
user->setPubkey( certificate.publicKey() );
|
||||
// TODO: Do not readd users
|
||||
m_users[ clientName ] = user;
|
||||
// TODO: ACL decision
|
||||
Tomahawk::APIv2::ACLJobStatusItem* job = new Tomahawk::APIv2::ACLJobStatusItem( user );
|
||||
JobStatusView::instance()->model()->addJob( job );
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Api_v2_0::jsonReply( QxtWebRequestEvent* event, const char* funcInfo, const QString& errorMessage, bool isError )
|
||||
{
|
||||
@ -120,10 +165,23 @@ Api_v2_0::jsonUnauthenticated( QxtWebRequestEvent *event )
|
||||
bool
|
||||
Api_v2_0::checkAuthentication( QxtWebRequestEvent* event )
|
||||
{
|
||||
if ( event->isSecure && !event->clientCertificate.isNull() )
|
||||
{
|
||||
// Using SSL Certificate authentication
|
||||
QString clientName = event->clientCertificate.subjectInfo( QSslCertificate::CommonName );
|
||||
QSslKey pubkey = event->clientCertificate.publicKey();
|
||||
if ( m_users.contains( clientName ) )
|
||||
{
|
||||
const QSharedPointer<Api2User> user = m_users.value( clientName );
|
||||
if ( user->aclDecision() == Api2User::FullAccess && user->pubkey() == pubkey )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
// TODO: Auth!
|
||||
// * SSL client certificate
|
||||
// * Shared secret between two clients when talking via SSL
|
||||
// * sth else when connecting without httpS
|
||||
// * a more secure version of digest auth
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
@ -19,7 +19,11 @@
|
||||
#ifndef API_V2_0_H
|
||||
#define API_V2_0_H
|
||||
|
||||
#include <QMap>
|
||||
#include <QObject>
|
||||
#include <QSharedPointer>
|
||||
|
||||
#include "Api2User.h"
|
||||
|
||||
class Api_v2;
|
||||
class QxtWebRequestEvent;
|
||||
@ -47,6 +51,16 @@ public slots:
|
||||
* This call needs to be authenticated.
|
||||
*/
|
||||
void playback( QxtWebRequestEvent* event, const QString& command );
|
||||
|
||||
/**
|
||||
* Request that the client should be authorized.
|
||||
*
|
||||
* The request can be made via 2 methods:
|
||||
* - If using SSL, the client sends his certificate as a standard peercerificate and supplies a shared secret.
|
||||
* - Without SSL, the client encrypts a shared secret with the certificate from the server and signs it with its secret.
|
||||
* The client certificate is supplied as another parameter
|
||||
*/
|
||||
void requestauth( QxtWebRequestEvent* event );
|
||||
private:
|
||||
/**
|
||||
* Check the current HTTP request is correctly authenticated via any of the possible authentication schemes.
|
||||
@ -66,6 +80,7 @@ private:
|
||||
void jsonUnauthenticated( QxtWebRequestEvent* event );
|
||||
|
||||
Api_v2* m_service;
|
||||
QMap< QString, QSharedPointer< Api2User > > m_users;
|
||||
};
|
||||
|
||||
#endif // API_V2_0_H
|
||||
|
146
src/tomahawk/web/apiv2/ACLItemDelegate.cpp
Normal file
146
src/tomahawk/web/apiv2/ACLItemDelegate.cpp
Normal file
@ -0,0 +1,146 @@
|
||||
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
|
||||
*
|
||||
* Copyright 2013, Uwe L. Korn <uwelk@xhochy.com>
|
||||
*
|
||||
* Tomahawk is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Tomahawk is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Tomahawk. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "ACLItemDelegate.h"
|
||||
|
||||
#include "jobview/JobStatusModel.h"
|
||||
#include "utils/TomahawkUtils.h"
|
||||
#include "utils/TomahawkUtilsGui.h"
|
||||
#include "ACLJobStatusItem.h"
|
||||
|
||||
#include <QApplication>
|
||||
#include <QMouseEvent>
|
||||
#include <QPainter>
|
||||
|
||||
namespace Tomahawk {
|
||||
namespace APIv2 {
|
||||
|
||||
#define PADDING 2
|
||||
|
||||
ACLItemDelegate::ACLItemDelegate( QObject *parent )
|
||||
: QStyledItemDelegate( parent )
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
ACLItemDelegate::~ACLItemDelegate()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
void ACLItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
|
||||
{
|
||||
ACLJobStatusItem* item = dynamic_cast< ACLJobStatusItem* >( index.data( JobStatusModel::JobDataRole ).value< JobStatusItem* >() );
|
||||
if ( !item )
|
||||
return;
|
||||
QStyleOptionViewItemV4 opt = option;
|
||||
initStyleOption( &opt, index );
|
||||
QFontMetrics fm( opt.font );
|
||||
|
||||
opt.state &= ~QStyle::State_MouseOver;
|
||||
QApplication::style()->drawPrimitive( QStyle::PE_PanelItemViewItem, &opt, painter, opt.widget );
|
||||
|
||||
painter->setRenderHint( QPainter::Antialiasing );
|
||||
painter->fillRect( opt.rect, Qt::lightGray );
|
||||
|
||||
QString mainText = QString( tr( "%An instance of\n%1\nwants to control this player:" ) ).arg( item->user()->clientName() );
|
||||
|
||||
const QRect rRect( opt.rect.left() + PADDING, opt.rect.top() + 4*PADDING, opt.rect.width() - 2*PADDING, opt.rect.height() - 2*PADDING );
|
||||
painter->drawText( rRect, Qt::AlignHCenter, mainText );
|
||||
|
||||
int totalwidth = opt.rect.width();
|
||||
int thirds = totalwidth/3;
|
||||
QRect allowBtnRect;
|
||||
painter->setPen( Qt::white );
|
||||
|
||||
QString allowBtnText = tr( "See Details & Decide" );
|
||||
int allowBtnWidth = fm.width( allowBtnText ) + 2 * PADDING;
|
||||
allowBtnRect = QRect( opt.rect.left() + thirds - allowBtnWidth / 2, opt.rect.bottom() - fm.height() - 4 * PADDING, allowBtnWidth + 2 * PADDING, fm.height() + 2 * PADDING );
|
||||
|
||||
|
||||
drawRoundedButton( painter, allowBtnRect, allowBtnRect.contains( m_savedHoverPos ) );
|
||||
painter->drawText( allowBtnRect, Qt::AlignCenter, allowBtnText );
|
||||
m_savedAcceptRect = allowBtnRect;
|
||||
}
|
||||
|
||||
|
||||
QSize
|
||||
ACLItemDelegate::sizeHint( const QStyleOptionViewItem& option, const QModelIndex& index) const
|
||||
{
|
||||
QSize size( QStyledItemDelegate::sizeHint( option, index ).width(), ( TomahawkUtils::defaultFontHeight() + 6 ) * 4.5 );
|
||||
return size;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ACLItemDelegate::emitSizeHintChanged( const QModelIndex& index )
|
||||
{
|
||||
emit sizeHintChanged( index );
|
||||
}
|
||||
|
||||
void
|
||||
ACLItemDelegate::drawRoundedButton( QPainter *painter, const QRect& btnRect, bool red ) const
|
||||
{
|
||||
//FIXME const colors
|
||||
if ( !red )
|
||||
TomahawkUtils::drawRoundedButton( painter, btnRect, QColor( 54, 127, 211 ), QColor( 43, 104, 182 ), QColor( 34, 85, 159 ), QColor( 35, 79, 147 ) );
|
||||
else
|
||||
TomahawkUtils::drawRoundedButton( painter, btnRect, QColor( 206, 63, 63 ), QColor( 170, 52, 52 ), QColor( 150, 50, 50 ), QColor( 130, 40, 40 ) );
|
||||
}
|
||||
|
||||
bool
|
||||
ACLItemDelegate::editorEvent( QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem& option, const QModelIndex& index )
|
||||
{
|
||||
Q_UNUSED( option )
|
||||
Q_UNUSED( model )
|
||||
//tDebug( LOGVERBOSE ) << Q_FUNC_INFO;
|
||||
if ( event->type() != QEvent::MouseButtonPress &&
|
||||
event->type() != QEvent::MouseButtonRelease &&
|
||||
event->type() != QEvent::MouseButtonDblClick &&
|
||||
event->type() != QEvent::MouseMove )
|
||||
return false;
|
||||
|
||||
if ( event->type() == QEvent::MouseMove )
|
||||
{
|
||||
QMouseEvent* me = static_cast< QMouseEvent* >( event );
|
||||
m_savedHoverPos = me->pos();
|
||||
//tDebug( LOGVERBOSE ) << Q_FUNC_INFO << "Setting position to " << m_savedHoverPos;
|
||||
emit update( index );
|
||||
return true;
|
||||
}
|
||||
|
||||
/* TODO
|
||||
if ( event->type() == QEvent::MouseButtonRelease || event->type() == QEvent::MouseButtonDblClick )
|
||||
{
|
||||
QMouseEvent* me = static_cast< QMouseEvent* >( event );
|
||||
if ( m_savedAcceptRect.contains( me->pos() ) )
|
||||
emit aclResult( Tomahawk::ACLStatus::Stream );
|
||||
else if ( m_savedDenyRect.contains( me->pos() ) )
|
||||
emit aclResult( Tomahawk::ACLStatus::Deny );
|
||||
return true;
|
||||
}
|
||||
*/
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
} // namespace APIv2
|
||||
} // namespace Tomahawk
|
60
src/tomahawk/web/apiv2/ACLItemDelegate.h
Normal file
60
src/tomahawk/web/apiv2/ACLItemDelegate.h
Normal file
@ -0,0 +1,60 @@
|
||||
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
|
||||
*
|
||||
* Copyright 2013, Uwe L. Korn <uwelk@xhochy.com>
|
||||
*
|
||||
* Tomahawk is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Tomahawk is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Tomahawk. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef TOMAHAWK_APIV2_ACLITEMDELEGATE_H
|
||||
#define TOMAHAWK_APIV2_ACLITEMDELEGATE_H
|
||||
|
||||
#include <QStyledItemDelegate>
|
||||
|
||||
#include "web/Api2User.h"
|
||||
|
||||
namespace Tomahawk {
|
||||
namespace APIv2 {
|
||||
|
||||
class ACLItemDelegate : public QStyledItemDelegate
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit ACLItemDelegate ( QObject* parent = 0 );
|
||||
virtual ~ACLItemDelegate();
|
||||
|
||||
virtual void paint( QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index ) const;
|
||||
virtual QSize sizeHint( const QStyleOptionViewItem& option, const QModelIndex& index ) const;
|
||||
|
||||
virtual void emitSizeHintChanged( const QModelIndex &index );
|
||||
|
||||
signals:
|
||||
void update( const QModelIndex& idx );
|
||||
void aclResult( Api2User::ACLDecision aclDecision );
|
||||
|
||||
protected:
|
||||
virtual bool editorEvent( QEvent* event, QAbstractItemModel* model, const QStyleOptionViewItem& option, const QModelIndex& index );
|
||||
|
||||
private:
|
||||
void drawRoundedButton( QPainter* painter, const QRect& btnRect, bool red = false ) const;
|
||||
|
||||
QPoint m_savedHoverPos;
|
||||
mutable QRect m_savedAcceptRect;
|
||||
};
|
||||
|
||||
} // namespace APIv2
|
||||
} // namespace Tomahawk
|
||||
|
||||
#endif // TOMAHAWK_APIV2_ACLITEMDELEGATE_H
|
56
src/tomahawk/web/apiv2/ACLJobStatusItem.cpp
Normal file
56
src/tomahawk/web/apiv2/ACLJobStatusItem.cpp
Normal file
@ -0,0 +1,56 @@
|
||||
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
|
||||
*
|
||||
* Copyright 2013, Uwe L. Korn <uwelk@xhochy.com>
|
||||
*
|
||||
* Tomahawk is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Tomahawk is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Tomahawk. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#include "ACLJobStatusItem.h"
|
||||
|
||||
#include "infosystem/InfoSystem.h"
|
||||
#include "ACLItemDelegate.h"
|
||||
|
||||
namespace Tomahawk {
|
||||
namespace APIv2 {
|
||||
|
||||
ACLJobStatusItem::ACLJobStatusItem( const QSharedPointer<Api2User>& user )
|
||||
: JobStatusItem()
|
||||
{
|
||||
m_user = user;
|
||||
}
|
||||
|
||||
|
||||
ACLJobStatusItem::~ACLJobStatusItem()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ACLJobStatusItem::createDelegate( QObject *parent )
|
||||
{
|
||||
if ( m_delegate )
|
||||
return;
|
||||
|
||||
m_delegate = new ACLItemDelegate( parent );
|
||||
|
||||
// Display a system notification so that the user sees that he has to make a decision.
|
||||
Tomahawk::InfoSystem::InfoPushData pushData( "ACLJobStatusItem", Tomahawk::InfoSystem::InfoNotifyUser, tr( "Tomahawk needs you to decide whether an app is allowed to connect via the HTTP API." ), Tomahawk::InfoSystem::PushNoFlag );
|
||||
Tomahawk::InfoSystem::InfoSystem::instance()->pushInfo( pushData );
|
||||
}
|
||||
|
||||
} // namespace APIv2
|
||||
} // namespace Tomahawk
|
||||
|
67
src/tomahawk/web/apiv2/ACLJobStatusItem.h
Normal file
67
src/tomahawk/web/apiv2/ACLJobStatusItem.h
Normal file
@ -0,0 +1,67 @@
|
||||
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
|
||||
*
|
||||
* Copyright 2013, Uwe L. Korn <uwelk@xhochy.com>
|
||||
*
|
||||
* Tomahawk is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Tomahawk is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Tomahawk. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef TOMAHAWK_APIV2_ACLJOBSTATUSITEM_H
|
||||
#define TOMAHAWK_APIV2_ACLJOBSTATUSITEM_H
|
||||
|
||||
#include "jobview/JobStatusItem.h"
|
||||
#include "web/Api2User.h"
|
||||
|
||||
#include <QPixmap>
|
||||
|
||||
namespace Tomahawk {
|
||||
namespace APIv2 {
|
||||
|
||||
class ACLJobStatusItem : public JobStatusItem
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit ACLJobStatusItem( const QSharedPointer<Api2User>& user );
|
||||
virtual ~ACLJobStatusItem();
|
||||
|
||||
virtual int weight() const { return 99; }
|
||||
|
||||
virtual QString rightColumnText() const { return QString(); }
|
||||
virtual QString mainText() const { return QString(); }
|
||||
virtual QPixmap icon() const { return QPixmap(); }
|
||||
virtual QString type() const { return "apiv2-acljob"; }
|
||||
|
||||
virtual int concurrentJobLimit() const { return 3; }
|
||||
|
||||
virtual bool hasCustomDelegate() const { return true; }
|
||||
virtual void createDelegate( QObject* parent = 0 );
|
||||
virtual QStyledItemDelegate* customDelegate() const { return m_delegate; }
|
||||
|
||||
virtual QSharedPointer<Api2User> user() const { return m_user; }
|
||||
virtual QString name() const { return m_user->name(); }
|
||||
|
||||
signals:
|
||||
// void userDecision( QSharedPointer<Api2User> user );
|
||||
|
||||
public slots:
|
||||
// void aclResult( Api2User::ACLDecision );
|
||||
|
||||
private:
|
||||
QStyledItemDelegate* m_delegate;
|
||||
QSharedPointer<Api2User> m_user;
|
||||
};
|
||||
|
||||
} // namespace APIv2
|
||||
} // namespace Tomahawk
|
||||
|
||||
#endif // TOMAHAWK_APIV2_ACLJOBSTATUSITEM_H
|
Loading…
x
Reference in New Issue
Block a user