From d9b3362e0c6a72390cb30a98afc98f6b04567af5 Mon Sep 17 00:00:00 2001 From: konrad Date: Sat, 1 Mar 2008 16:53:35 +0000 Subject: [PATCH] add password change git-svn-id: https://silmor.de/svn/softmagic/smoke/trunk@99 6e3c4bff-ac9f-4ac1-96c5-d2ea494d3e33 --- doc/prog_protocol.html | 24 ++++++++++- src/overview.cpp | 97 ++++++++++++++++++++++++++++++++++++++++++- src/overview.h | 24 +++++++++++ src/user.cpp | 23 ++++++++++- src/user.h | 7 ++- src/webrequest.cpp | 16 +++++++ src/webrequest.h | 2 + www/inc/machine/session.php | 78 ++++++++++++++++++++++++++++++++++- www/machine.php | 12 +++++- 9 files changed, 275 insertions(+), 8 deletions(-) diff --git a/doc/prog_protocol.html b/doc/prog_protocol.html index 1b7ca1a..b6f2e7b 100644 --- a/doc/prog_protocol.html +++ b/doc/prog_protocol.html @@ -261,11 +261,13 @@ Both calls use this structure for the request:

 <Users>
-  <User name="loginname">Description of User</User>
+  <User name="loginname" passwd="initial password">Description of User</User>
   ...
 </Users>
 
+The passwd attribute is optional.

+ The adduser call also uses it for the response, leaving out any user name that already existed or does not conform to the syntax requirements.

Deleting a User

@@ -276,6 +278,26 @@ FIXME: this call can fail silently if the user is still referenced somewhere. Th FIXME 2: currently this transaction is not atomic for a reason: if it fails to delete the user it will at least succeed in deleting its access rights. +

Changing a Users own Password

+ +The setmypasswd can be used to change the user of the current session. The request looks like:

+ +

+<SetMyPasswd oldpwd="old password" newpwd="new password"\>
+
+ +The response is empty. Only the status counts. + +

Changing another Users Password

+ +The setpasswd can be used to change the user of the current session. The request looks like:

+ +

+<SetPasswd user="user name" newpwd="new password"\>
+
+ +The response is empty. Only the status counts. +

Getting User ACLs

The getuseracl transaction returns the ACL of a specific user. The request contains only the login name of the user. The response looks like:

diff --git a/src/overview.cpp b/src/overview.cpp index 1884745..f3da814 100644 --- a/src/overview.cpp +++ b/src/overview.cpp @@ -45,6 +45,7 @@ MOverview::MOverview(MWebRequest*mw,QString pk) QMenu*m=mb->addMenu(tr("&Session")); m->addAction(tr("&Re-Login"),this,SLOT(relogin())); m->addAction(tr("&Offline mode"))->setEnabled(false); + m->addAction(tr("Change my &Password"),this,SLOT(setMyPassword())) ->setEnabled(req->hasRole("setmypasswd")); m->addSeparator(); m->addAction(tr("&Close Session"),this,SLOT(close())); @@ -85,7 +86,9 @@ MOverview::MOverview(MWebRequest*mw,QString pk) connect(p,SIGNAL(clicked()),this,SLOT(editEvent())); p->setEnabled(req->hasRole("geteventdata")); vl->addSpacing(15); - vl->addWidget(new QPushButton(tr("Order Ticket...")),0); + vl->addWidget(p=new QPushButton(tr("Order Ticket...")),0); + connect(p,SIGNAL(clicked()),this,SLOT(eventOrderTicket())); + p->setEnabled(req->hasRole("createorder")); vl->addStretch(10); tab->addTab(carttab=new QWidget,tr("Shopping Cart")); @@ -147,6 +150,9 @@ MOverview::MOverview(MWebRequest*mw,QString pk) vl->addWidget(p=new QPushButton(tr("Roles...")),0); connect(p,SIGNAL(clicked()),this,SLOT(editUserRoles())); p->setEnabled(req->hasRole("getuseracl")); + vl->addWidget(p=new QPushButton(tr("Set Password...")),0); + connect(p,SIGNAL(clicked()),this,SLOT(setUserPassword())); + p->setEnabled(req->hasRole("setpasswd")); vl->addStretch(10); //host tab @@ -189,6 +195,10 @@ MOverview::MOverview(MWebRequest*mw,QString pk) eventtab->setEnabled(false); tab->setTabEnabled(tab->indexOf(eventtab),false); } + if(!req->hasRole("createorder")){ + carttab->setEnabled(false); + tab->setTabEnabled(tab->indexOf(carttab),false); + } if(req->hasRole("getusers")){ updateUsers(); }else{ @@ -290,8 +300,10 @@ void MOverview::newUser() if(QMessageBox::warning(this,tr("Error"),tr("The user name must contain only letters, digits, and underscores and must be at least one character long!"),QMessageBox::Retry|QMessageBox::Abort)!=QMessageBox::Retry) return; } + //get password + QString pwd=QInputDialog::getText(this,tr("Password"),tr("Please enter an initial password for the user:"),QLineEdit::Password); //send request - MUser(req,name).create(); + MUser(req,name).create(pwd); //update display updateUsers(); } @@ -357,6 +369,34 @@ void MOverview::editUserHosts() usr.setHosts(cd.getCheckList()); } +void MOverview::setMyPassword() +{ + MPasswordChange pc(this); + if(pc.exec()==QDialog::Accepted){ + QString e=req->changeMyPassword(pc.oldPassword(),pc.newPassword()); + if(e!="") + QMessageBox::warning(this,tr("Warning"),tr("Error setting password: %1").arg(e)); + } +} +void MOverview::setUserPassword() +{ + //get selection + QModelIndex sel=usertable->currentIndex(); + if(!sel.isValid())return; + //get uname + QString name=usermodel->data(usermodel->index(sel.row(),0)).toString(); + //get new password + MPasswordChange pc(this,name); + if(pc.exec()!=QDialog::Accepted)return; + QString p=pc.newPassword(); + if(p==""){ + QMessageBox::warning(this,tr("Warning"),tr("The password must be non-empty and both lines must match")); + return; + } + //... + MUser usr(req,name); + usr.changePassword(p); +} void MOverview::updateHosts() { @@ -521,3 +561,56 @@ void MOverview::exportHost() fd.write(out.toAscii()); fd.close(); } + + +void MOverview::eventOrderTicket() +{ +} + + +/**********************************************/ + +MPasswordChange::MPasswordChange(QWidget*par,QString user) + :QDialog(par) +{ + oldpwd=newpwd1=newpwd2=0; + if(user=="") + setWindowTitle(tr("Change my password")); + else + setWindowTitle(tr("Reset password of user %1").arg(user)); + QGridLayout*gl; + setLayout(gl=new QGridLayout); + if(user==""){ + gl->addWidget(new QLabel(tr("Old Password:")),0,0); + gl->addWidget(oldpwd=new QLineEdit,0,1); + oldpwd->setEchoMode(QLineEdit::Password); + } + gl->addWidget(new QLabel(tr("New Password:")),1,0); + gl->addWidget(newpwd1=new QLineEdit,1,1); + newpwd1->setEchoMode(QLineEdit::Password); + gl->addWidget(new QLabel(tr("Repeat Password:")),2,0); + gl->addWidget(newpwd2=new QLineEdit,2,1); + newpwd2->setEchoMode(QLineEdit::Password); + + QHBoxLayout*hl; + gl->addLayout(hl=new QHBoxLayout,3,0,1,2); + hl->addStretch(10); + QPushButton*p; + hl->addWidget(p=new QPushButton(tr("Set Password"))); + connect(p,SIGNAL(clicked()),this,SLOT(accept())); + hl->addWidget(p=new QPushButton(tr("Cancel"))); + connect(p,SIGNAL(clicked()),this,SLOT(reject())); +} + +QString MPasswordChange::oldPassword() +{ + if(oldpwd)return oldpwd->text(); + return ""; +} + +QString MPasswordChange::newPassword() +{ + if(newpwd1==0 || newpwd2==0)return ""; + if(newpwd1->text()!=newpwd2->text())return ""; + return newpwd1->text(); +} diff --git a/src/overview.h b/src/overview.h index 5f99fbc..b58f75b 100644 --- a/src/overview.h +++ b/src/overview.h @@ -15,12 +15,14 @@ #include #include +#include class MWebRequest; class QTabWidget; class QTableView; class QStandardItemModel; class QPushButton; +class QLineEdit; /**Main Overview Window*/ class MOverview:public QMainWindow @@ -43,6 +45,8 @@ class MOverview:public QMainWindow void editEvent(); /**update list of events*/ void updateEvents(); + /**order ticket from event tab*/ + void eventOrderTicket(); /**update list of users*/ void updateUsers(); @@ -56,6 +60,10 @@ class MOverview:public QMainWindow void editUserRoles(); /**set users hosts*/ void editUserHosts(); + /**set my own password*/ + void setMyPassword(); + /**set a users password*/ + void setUserPassword(); /**update list of hosts*/ void updateHosts(); @@ -85,4 +93,20 @@ class MOverview:public QMainWindow QPushButton*thishostbutton; }; +/**Helper dialog for changing passwords*/ +class MPasswordChange:public QDialog +{ + Q_OBJECT + public: + /**creates a password change dialog, if user is empty it is presumed to change own password*/ + MPasswordChange(QWidget*parent,QString user=QString()); + + /**if own password: return old password*/ + QString oldPassword(); + /**returns new password, or empty if the two lines don't match*/ + QString newPassword(); + private: + QLineEdit *oldpwd,*newpwd1,*newpwd2; +}; + #endif diff --git a/src/user.cpp b/src/user.cpp index f364241..327c14d 100644 --- a/src/user.cpp +++ b/src/user.cpp @@ -57,7 +57,7 @@ bool MUser::isValid() return QRegExp("[A-Za-z0-9_]+").exactMatch(m_userid); } -bool MUser::create() +bool MUser::create(QString pwd) { //do not attempt to save invalid or incomplete data if(!isValid())return false; @@ -66,6 +66,7 @@ bool MUser::create() QDomElement root=doc.createElement("Users"); QDomElement el=doc.createElement("User"); el.setAttribute("name",m_userid); + el.setAttribute("passwd",pwd); el.appendChild(doc.createTextNode(m_descr)); root.appendChild(el); doc.appendChild(root); @@ -80,6 +81,26 @@ bool MUser::create() } } +bool MUser::changePassword(QString pwd) +{ + //do not attempt to save invalid or incomplete data + if(!isValid())return false; + //create XML + QDomDocument doc; + QDomElement el=doc.createElement("SetPasswd"); + el.setAttribute("user",m_userid); + el.setAttribute("newpwd",pwd); + doc.appendChild(el); + //call + req->request("setpasswd",doc.toByteArray()); + //check success + if(req->responseStatus()==MWebRequest::Ok){ + return true; + }else{ + return false; + } +} + void MUser::deleteUser() { if(!isValid())return; diff --git a/src/user.h b/src/user.h index 8db084d..eb61f8f 100644 --- a/src/user.h +++ b/src/user.h @@ -40,8 +40,8 @@ class MUser /**checks user name*/ bool isValid(); - /**creates user in database; returns true on success*/ - bool create(); + /**creates user in database with an initial password; returns true on success*/ + bool create(QString pwd); /**deletes user from database*/ void deleteUser(); @@ -61,6 +61,9 @@ class MUser /**send the updated host list of the user to the server; returns true on success*/ bool setHosts(const MCheckList&); + /**change the password of this user; returns whether successful*/ + bool changePassword(QString); + private: MWebRequest*req; QString m_userid,m_descr; diff --git a/src/webrequest.cpp b/src/webrequest.cpp index b2e8b21..526f5ed 100644 --- a/src/webrequest.cpp +++ b/src/webrequest.cpp @@ -271,6 +271,22 @@ bool MWebRequest::relogin() return doLogin(); } +QString MWebRequest::changeMyPassword(QString o,QString n) +{ + //check old + if(passwd!=o)return tr("Cannot change password, old password does not match!"); + //create DOM tree + QDomDocument doc; + QDomElement el=doc.createElement("SetMyPasswd"); + el.setAttribute("oldpwd",o); + el.setAttribute("newpwd",n); + doc.appendChild(el); + //request + request("setmypasswd",doc.toByteArray()); + if(responseStatus()==MWebRequest::Ok)return ""; + else return tr(rspdata.data()); +} + QString MWebRequest::errorString() { return errstr; diff --git a/src/webrequest.h b/src/webrequest.h index 5d9a237..ef3f60d 100644 --- a/src/webrequest.h +++ b/src/webrequest.h @@ -97,6 +97,8 @@ class MWebRequest:public QObject bool relogin(); /**log out of web server*/ void logout(); + /**change password; returns error string if it fails, empty if it succeeds*/ + QString changeMyPassword(QString oldpwd,QString newpwd); private slots: /**internal: used by wait loop for web requests*/ diff --git a/www/inc/machine/session.php b/www/inc/machine/session.php index 8a3b4f9..32c563b 100644 --- a/www/inc/machine/session.php +++ b/www/inc/machine/session.php @@ -195,6 +195,50 @@ class Session echo $tout; } + /**set my own password*/ + public function setMyPasswd($txt) + { + //check whether I really can do that + if(!$this->isAuthenticated()){ + header("X-MagicSmoke-Status: Unauthenticated"); + die("Not authenticated. Can't change password."); + } + //parse XML + $dom=new DOMDocument; + if(!$dom->loadXML($txt)){ + header("X-MagicSmoke-Status: SyntaxError"); + die("unable to parse XML data"); + } + $nl=$dom->getElementsByTagName("SetMyPasswd"); + if($nl->length!=1){ + header("X-MagicSmoke-Status: SyntaxError"); + die("expected exactly one passwd element"); + } + $spw=$nl->item(0); + $old=$spw->getAttribute("oldpwd"); + $nwp=$spw->getAttribute("newpwd"); + //sanity check + if($nwp==""){ + header("X-MagicSmoke-Status: SyntaxError"); + die("cannot set an empty password"); + } + //check old password + global $db; + $res=$db->select("users","passwd","uname=".$db->escapeString($this->user)); + if(count($res)!=1){ + header("X-MagicSmoke-Status: Error"); + die("Ooops. Unable to find user. You have been deleted."); + } + if($old!=$res[0]["passwd"]){ + header("X-MagicSmoke-Status: Error"); + deleteSession(); + die("Wrong password. Session hijacked, terminating it."); + } + //set new password + $db->update("users",array("passwd"=>$nwp),"uname=".$db->escapeString($this->user)); + header("X-MagicSmoke-Status: Ok"); + } + /**checks whether user can execute this transaction, returns true on success; it always returns true for admins*/ public function canExecute($transaction) { @@ -411,6 +455,7 @@ function parseUserXml($txt) foreach($xml->getElementsByTagName("User") as $el){ $usr["name"]=$el->getAttribute("name"); $usr["descr"]=""; + $usr["passwd"]=$el->getAttribute("passwd"); foreach($el->childNodes as $cn) if($cn->nodeType==XML_TEXT_NODE) $usr["descr"]=$cn->wholeText; @@ -445,7 +490,7 @@ function addUserXml($txt) $res=$db->select("users","uname","uname='".$usr[$i]["name"]."'"); if(count($res)==0){ //create new - $db->insert("users",array("uname"=>$usr[$i]["name"],"description"=>$usr[$i]["descr"])); + $db->insert("users",array("uname"=>$usr[$i]["name"],"description"=>$usr[$i]["descr"],"passwd"=>$usr[$i]["passwd"])); //print data $udm=$dom->createElement("User",$usr[$i]["descr"]); $udm->setAttributeNode(new DOMAttr("name",$usr[$i]["name"])); @@ -475,4 +520,35 @@ function deleteUserXml($txt) header("X-MagicSmoke-Status: Ok"); } +//set another users passwd +function setPasswdXml($txt) +{ + global $db; + //parse XML + $dom=new DOMDocument; + if(!$dom->loadXML($txt)){ + header("X-MagicSmoke-Status: SyntaxError"); + die("unable to parse XML data"); + } + $nl=$dom->getElementsByTagName("SetPasswd"); + if($nl->length!=1){ + header("X-MagicSmoke-Status: SyntaxError"); + die("expected exactly one passwd element"); + } + $spw=$nl->item(0); + $usr=$spw->getAttribute("user"); + $nwp=$spw->getAttribute("newpwd"); + //sanity check + if($nwp==""){ + header("X-MagicSmoke-Status: SyntaxError"); + die("cannot set an empty password"); + } + //set new password + if($db->update("users",array("passwd"=>$nwp),"uname=".$db->escapeString($usr))===false){ + header("X-MagicSmoke-Status: Error"); + die("Unable to change this password."); + }else + header("X-MagicSmoke-Status: Ok"); +} + ?> \ No newline at end of file diff --git a/www/machine.php b/www/machine.php index 835e419..b52adc3 100644 --- a/www/machine.php +++ b/www/machine.php @@ -18,7 +18,7 @@ $ALLOWEDREQUESTS=array( //all requests below here need authentication tr("getmyroles"), //role management: get my own ACLs //all requests below here need a role entry in the DB - tr("getusers"),tr("setuserdescription"),tr("getuseracl"),tr("setuseracl"),tr("getuserhosts"),tr("setuserhosts"),tr("adduser"),tr("deleteuser"),//user management + tr("getusers"),tr("setuserdescription"),tr("getuseracl"),tr("setuseracl"),tr("getuserhosts"),tr("setuserhosts"),tr("adduser"),tr("deleteuser"),tr("setmypasswd"),tr("setpasswd"),//user management tr("gethosts"),tr("sethost"),tr("addhost"),tr("deletehost"), //host management tr("geteventlist"),tr("geteventdata"),tr("seteventdata"), //event infos tr("getroomdata"),tr("setroomdata"),//room infos @@ -183,6 +183,16 @@ if($SMOKEREQUEST=="deleteuser"){ deleteUserXml($REQUESTDATA); exit(); } +//set my own password +if($SMOKEREQUEST=="setmypasswd"){ + $session->setMyPasswd($REQUESTDATA); + exit(); +} +//reset another users password +if($SMOKEREQUEST=="setpasswd"){ + setPasswdXml($REQUESTDATA); + exit(); +} //return a list of all hosts with their keys // there is currently no transaction to get names only, since this is -- 1.7.2.5