{% extends "base.html" %}
-{% block title %}{{ _("Log In") }}{% end block %}
+{% block title %}{{ _("Sign In") }}{% end block %}
-{% block container %}
- <div class="grid-x grid-padding-x align-center">
- <div class="cell medium-6">
- <div class="callout">
- <h3>{{ _("Log In") }}</h3>
+{% block body %}
+ <section class="section">
+ <div class="container">
+ <div class="columns is-centered">
+ <div class="column is-one-third">
+ <h1 class="title is-1">{{ _("Sign In") }}</h1>
- {% if failed %}
- <p>{{ _("Login failed") }}</p>
- {% end %}
+ <form method="POST" action="">
+ {% raw xsrf_form_html() %}
- <form method="POST" action="">
- {% raw xsrf_form_html() %}
+ <div class="field">
+ <p class="control has-icons-left">
+ <input class="input {% if failed %}is-danger{% end %}"
+ type="text" name="username" placeholder="{{ _("Username") }}"
+ {% if username %}value="{{ username }}"{% end %}>
+ <span class="icon is-small is-left">
+ <i class="fas fa-user"></i>
+ </span>
+ </p>
+ </div>
- <input type="text" name="username"
- placeholder="{{ _("Username") }}" required>
+ <div class="field">
+ <p class="control has-icons-left">
+ <input class="input {% if failed %}is-danger{% end %}"
+ type="password" name="password" placeholder="{{ _("Password") }}">
+ <span class="icon is-small is-left">
+ <i class="fas fa-lock"></i>
+ </span>
+ </p>
+ </div>
- <input type="password" name="password"
- placeholder="{{ _("Password") }}" required>
-
- <button type="submit" class="primary button">{{ _("Log In") }}</button>
- </form>
+ <div class="field">
+ <p class="control">
+ <button class="button is-primary is-fullwidth">
+ {{ _("Sign In") }}
+ </button>
+ </p>
+ </div>
+ </form>
+ </div>
</div>
</div>
- </div>
+ </section>
{% end %}
log = logging.getLogger("pbs.web.auth")
class LoginHandler(base.KerberosAuthMixin, base.BaseHandler):
- def get(self):
- username = self.get_authenticated_user()
- if not username:
- # Ask to authenticate
- self.authenticate_redirect()
- return
+ def get(self, username=None, failed=False):
+ if self.current_user:
+ raise tornado.web.HTTPError(403, "Already logged in")
+
+ self.render("login.html", username=username, failed=failed)
+
+ @base.ratelimit(requests=10, minutes=5)
+ def post(self):
+ # Fetch credentials
+ username = self.get_argument("username")
+ password = self.get_argument("password")
- # Strip the realm
- username, delim, realm = username.partition("@")
+ # Try to authenticate the user
+ if not self._auth_with_credentials(username, password):
+ return self.get(username=username, failed=True)
+ # If the authentication was successful, we create a new session
with self.db.transaction():
- # Otherwise fetch the authenticated user
+ # Fetch the authenticated user
user = self.backend.users.get_by_name(username)
if not user:
raise tornado.web.HTTPError(500, "Could not find user %s" % username)
return
# Perform GSS API Negotiation
- if auth_header.startswith("Negotiate"):
+ if auth_header.startswith("Negotiate "):
return self._auth_negotiate(auth_header)
# Perform Basic Authentication
except:
raise tornado.web.HTTPError(400, "Authorization data was malformed")
+ # Authenticate against Kerberos
+ return self._auth_with_credentials(username, password)
+
+ def _auth_with_credentials(self, username, password):
# Check the credentials against the Kerberos database
try:
kerberos.checkPassword(username, password,