# HG changeset patch # User Tomas Zeman # Date 1334903184 -7200 # Node ID 3a53fa30e03e1b728f891b83272893b322d7c716 # Parent b1dc0efd1303e49b72f79d43a07e87f078f1b482 Authentication diff -r b1dc0efd1303 -r 3a53fa30e03e src/main/scala/bootstrap/liftweb/Boot.scala --- a/src/main/scala/bootstrap/liftweb/Boot.scala Fri Apr 20 08:26:24 2012 +0200 +++ b/src/main/scala/bootstrap/liftweb/Boot.scala Fri Apr 20 08:26:24 2012 +0200 @@ -17,7 +17,8 @@ import fis.base.model._ import fis.base.ui._ -import fis.aaa.ui.UserSnippet +import fis.aaa.model._ +import fis.aaa.ui._ import fis.crm.ui._ import fis.geo.ui.{CitySnippet, CountrySnippet} import fis.db.SquerylTxMgr @@ -39,12 +40,20 @@ import Loc._ + AuthnSnippet.init() SecNav.init() + /* Authn wiring */ + UserVendors.cur.default.set(Vendor(() => AuthnSnippet.cur)) + AuthnSnippet. + registerAuthenticator(FetchUserAuthenticator). + registerAuthenticator(PasswordAuthenticator) + val menus = List(Menu("/", "FIS Main page") / "index" >> Hidden, Menu.i("Home") / "" , ContactSnippet.menu, CompanySnippet.menu, UserSnippet.menu, + AuthnSnippet.menu, CountrySnippet.menu, CitySnippet.menu) diff -r b1dc0efd1303 -r 3a53fa30e03e src/main/scala/fis/aaa/model/Authenticator.scala --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/scala/fis/aaa/model/Authenticator.scala Fri Apr 20 08:26:24 2012 +0200 @@ -0,0 +1,69 @@ +/* + * Copyright 2012 Tomas Zeman + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package fis.aaa.model + +import net.liftweb.common._ +import net.liftweb.http._ +import net.liftweb.util._ +import net.liftweb.util.Helpers._ +import net.tz.lift.model._ +import scala.collection.mutable.ArrayStack + +trait Authenticator { + def authenticate(u: User, p: String): Box[User] +} + +trait StackableAuthenticator extends Authenticator { + private val stack = new ArrayStack[Authenticator] + + def registerAuthenticator(auth: Authenticator): StackableAuthenticator = { + stack += auth + this + } + + def authenticate(in: User, p: String): Box[User] = + authn(stack.iterator, Full(in), p) + + private def authn(it: Iterator[Authenticator], u: Box[User], p: String): + Box[User] = + if (!it.hasNext || u.isEmpty) { + u + } else { + val n = u flatMap { v => it.next.authenticate(v, p) } + authn(it, n, p) + } +} + +object FetchUserAuthenticator extends Authenticator with UserCrud { + def authenticate(u: User, p: String): Box[User] = byLogin(u.login.get) $ { + _ match { + case Failure(_, _, _) => S error l10n("error.user-fetch") + case Empty => S error l10n("error.user-not-exist") + case _ => // empty + }} +} + +object PasswordAuthenticator extends Authenticator with UserCrud with Loggable { + def authenticate(u: User, p: String): Box[User] = byLogin(u.login.get) flatMap { u => + logger.debug("Pass: '%s' '%s' '%s'".format(p, md5(p), u.password.get)) + ((p.length > 0) && (u.password.get == md5(p))).box(u) $ { _ match { + case Full(_) => // ok + case _ => S error l10n("error.invalid-password") + }} + } +} + +// vim: set ts=2 sw=2 et: diff -r b1dc0efd1303 -r 3a53fa30e03e src/main/scala/fis/aaa/model/UserCrud.scala --- a/src/main/scala/fis/aaa/model/UserCrud.scala Fri Apr 20 08:26:24 2012 +0200 +++ b/src/main/scala/fis/aaa/model/UserCrud.scala Fri Apr 20 08:26:24 2012 +0200 @@ -16,9 +16,13 @@ package fis.aaa.model import fis.base.model.RecordCrud +import net.liftweb.common._ +import net.liftweb.squerylrecord.RecordTypeMode._ trait UserCrud extends RecordCrud[User] { val table = AaaSchema.userT + def byLogin(l: String): Box[User] = from(table)(u => + where(u.deleted === false and u.login === l) select(u)) headOption } object UserCrud extends UserCrud diff -r b1dc0efd1303 -r 3a53fa30e03e src/main/scala/fis/aaa/ui/AuthnSnippet.scala --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/scala/fis/aaa/ui/AuthnSnippet.scala Fri Apr 20 08:26:24 2012 +0200 @@ -0,0 +1,94 @@ +/* + * Copyright 2012 Tomas Zeman + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package fis.aaa.ui + +import fis.aaa.model._ +import fis.base.ui.EntityLink +import net.liftweb.common._ +import net.liftweb.http._ +import net.liftweb.sitemap._ +import net.liftweb.sitemap.Loc._ +import net.liftweb.squerylrecord.RecordTypeMode._ +import net.liftweb.util._ +import net.liftweb.util.Helpers._ +import net.tz.lift.model._ +import net.tz.lift.snippet._ +import scala.xml.{NodeSeq, Text} + +/** + * Login/logout snippet. + */ +object AuthnSnippet extends UserCrud with Loggable with + StackableAuthenticator { + + object cur extends SessionVar[Box[User]](Empty) + object whence extends RequestVar[String](S.referer openOr "/") + + val loginOp = Menu("login.title", l10n("login.title")) / "login" >> + locTpl("login") >> Snippet("form", render) >> Hidden + + val logoutOp = Menu("logout.title", l10n("logout.title")) / "logout" >> + EarlyResponse({() => + cur(None) + Full(RedirectWithState("/", RedirectState(Empty, + l10n("logout.success") -> NoticeType.Notice))) + }) >> Hidden + + val menu = loginOp submenus (logoutOp) + + def init() { + LiftRules.snippets.append { + case List("user-label") => userLabel + } + } + + private def render: CssTr = { + for { + r <- S.request if r.post_? + un <- S.param("login") $ { + case Full("") | Empty => S error l10n("error.login.required") + case _ => + } if un.length > 0 + pass <- S.param("pass") $ { + case Full("") | Empty => S error l10n("error.password.required") + case _ => + } if pass.length > 0 + } { + cur(authenticate(User.createRecord.login(un), pass)) + cur map { _ => + S notice l10n("login.welcome") + S.redirectTo(whence) + } + } + ("#login [value]" #> S.param("login") & + "#whence" #> SHtml.hidden(whence(_), whence)) + } + + private val lpars = "rel" -> "nofollow,noindex" + + private def userLabel: CssTr = "*" #> (User.get match { + case Full(u) => + val l = logoutOp.loc + i18n("logged.as") ++ EntityLink(u).map(_.asHtml) ++ Text(" [") ++ + (a(l.calcDefaultHref)(l.linkText openOr NodeSeq.Empty) % lpars) ++ + Text("]") + case _ => + val l = loginOp.loc + a(l.calcDefaultHref)(l.linkText openOr NodeSeq.Empty) % lpars + }) +} + +// vim: set ts=2 sw=2 et: diff -r b1dc0efd1303 -r 3a53fa30e03e src/main/webapp/css/base.css --- a/src/main/webapp/css/base.css Fri Apr 20 08:26:24 2012 +0200 +++ b/src/main/webapp/css/base.css Fri Apr 20 08:26:24 2012 +0200 @@ -1,5 +1,5 @@ /* - * Copyright 2011 Tomas Zeman + * Copyright 2011-2012 Tomas Zeman * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -73,3 +73,7 @@ .sf-menu span { padding: 0.75em 1em; } + +#user-label { + font-size: 12px; +} diff -r b1dc0efd1303 -r 3a53fa30e03e src/main/webapp/login.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/webapp/login.html Fri Apr 20 08:26:24 2012 +0200 @@ -0,0 +1,38 @@ + + + + + Fis login + + +
+
+
+
+ +
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+
+ + +
+
+ + diff -r b1dc0efd1303 -r 3a53fa30e03e src/main/webapp/templates-hidden/_resources.html --- a/src/main/webapp/templates-hidden/_resources.html Fri Apr 20 08:26:24 2012 +0200 +++ b/src/main/webapp/templates-hidden/_resources.html Fri Apr 20 08:26:24 2012 +0200 @@ -9,6 +9,19 @@ Add Name + + Log In + Log Out + Welcome! + You were successfully logged out. + Logged as + Log In + Login value required. + Password required. + Error while retrieving user from database. + User does not exist. + Invalid password. + <-- contact --> Contact diff -r b1dc0efd1303 -r 3a53fa30e03e src/main/webapp/templates-hidden/_resources_cs.html --- a/src/main/webapp/templates-hidden/_resources_cs.html Fri Apr 20 08:26:24 2012 +0200 +++ b/src/main/webapp/templates-hidden/_resources_cs.html Fri Apr 20 08:26:24 2012 +0200 @@ -10,6 +10,20 @@ Název + + Log In + Log Out + Vítejte! + Byli jste úspěšně odhlášeni. + Přihlášen jako + Log In + Login je povinný. + Heslo je povinné. + Chyba při načítání uživatele. + Uživatel neexistuje. + Nesprávné heslo. + + <-- contact --> Kontakt Kontakt %s diff -r b1dc0efd1303 -r 3a53fa30e03e src/main/webapp/templates-hidden/default.html --- a/src/main/webapp/templates-hidden/default.html Fri Apr 20 08:26:24 2012 +0200 +++ b/src/main/webapp/templates-hidden/default.html Fri Apr 20 08:26:24 2012 +0200 @@ -25,6 +25,9 @@

Functional Information System

Project management, CRM, ...

+

+ +