]>
git.ipfire.org Git - ipfire.org.git/blob - src/web/auth.py
9e3bf7127208df1c1673916c131c40fa5134975f
9 class AuthenticationMixin(object):
10 def login(self
, account
):
11 # User has logged in, create a session
12 session_id
, session_expires
= self
.backend
.accounts
.create_session(
13 account
, self
.request
.host
)
15 # Check if a new session was created
17 raise tornado
.web
.HTTPError(500, "Could not create session")
19 # Send session cookie to the client
20 self
.set_cookie("session_id", session_id
,
21 domain
=self
.request
.host
, expires
=session_expires
, secure
=True)
24 session_id
= self
.get_cookie("session_id")
28 success
= self
.backend
.accounts
.destroy_session(session_id
, self
.request
.host
)
30 self
.clear_cookie("session_id")
33 class LoginHandler(AuthenticationMixin
, base
.BaseHandler
):
35 next
= self
.get_argument("next", None)
37 self
.render("auth/login.html", next
=next
,
38 incorrect
=False, username
=None)
40 @base.ratelimit(minutes
=15, requests
=10)
42 username
= self
.get_argument("username")
43 password
= self
.get_argument("password")
44 next
= self
.get_argument("next", "/")
47 account
= self
.backend
.accounts
.auth(username
, password
)
49 logging
.error("Unknown user or invalid password: %s" % username
)
54 # Render login page again
55 return self
.render("auth/login.html",
56 incorrect
=True, username
=username
, next
=next
,
60 with self
.db
.transaction():
64 return self
.redirect(next
)
67 class LogoutHandler(AuthenticationMixin
, base
.BaseHandler
):
69 with self
.db
.transaction():
72 # Get back to the start page
76 class RegisterHandler(base
.BaseHandler
):
78 # Redirect logged in users away
83 self
.render("auth/register.html")
85 @base.ratelimit(minutes
=15, requests
=5)
87 uid
= self
.get_argument("uid")
88 email
= self
.get_argument("email")
90 first_name
= self
.get_argument("first_name")
91 last_name
= self
.get_argument("last_name")
95 with self
.db
.transaction():
96 self
.backend
.accounts
.register(uid
, email
,
97 first_name
=first_name
, last_name
=last_name
,
98 country_code
=self
.current_country_code
)
99 except ValueError as e
:
100 raise tornado
.web
.HTTPError(400, "%s" % e
) from e
102 self
.render("auth/register-success.html")
105 class ActivateHandler(AuthenticationMixin
, base
.BaseHandler
):
106 def get(self
, uid
, activation_code
):
107 self
.render("auth/activate.html")
109 def post(self
, uid
, activation_code
):
110 password1
= self
.get_argument("password1")
111 password2
= self
.get_argument("password2")
113 if not password1
== password2
:
114 raise tornado
.web
.HTTPError(400, "Passwords do not match")
116 with self
.db
.transaction():
117 account
= self
.backend
.accounts
.activate(uid
, activation_code
)
119 raise tornado
.web
.HTTPError(400, "Account not found: %s" % uid
)
121 # Set the new password
122 account
.passwd(password1
)
127 # Redirect to success page
128 self
.render("auth/activated.html", account
=account
)
131 class PasswordResetInitiationHandler(base
.BaseHandler
):
133 username
= self
.get_argument("username", None)
135 self
.render("auth/password-reset-initiation.html", username
=username
)
137 @base.ratelimit(minutes
=15, requests
=10)
139 username
= self
.get_argument("username")
141 # Fetch account and submit password reset
142 account
= self
.backend
.accounts
.get_by_uid(username
)
144 with self
.db
.transaction():
145 account
.request_password_reset()
147 self
.render("auth/password-reset-successful.html")
150 class PasswordResetHandler(AuthenticationMixin
, base
.BaseHandler
):
151 def get(self
, uid
, reset_code
):
152 account
= self
.backend
.accounts
.get_by_uid(uid
)
154 raise tornado
.web
.HTTPError(404, "Could not find account: %s" % uid
)
156 self
.render("auth/password-reset.html", account
=account
)
158 def post(self
, uid
, reset_code
):
159 account
= self
.backend
.accounts
.get_by_uid(uid
)
161 raise tornado
.web
.HTTPError(404, "Could not find account: %s" % uid
)
163 password1
= self
.get_argument("password1")
164 password2
= self
.get_argument("password2")
166 if not password1
== password2
:
167 raise tornado
.web
.HTTPError(400, "Passwords do not match")
169 # Try to perform password reset
170 with self
.db
.transaction():
171 account
.reset_password(reset_code
, password1
)
173 # Login the user straight away after reset was successful
180 class SSODiscourse(base
.BaseHandler
):
181 @base.ratelimit(minutes
=24*60, requests
=100)
182 @tornado.web
.authenticated
184 # Fetch Discourse's parameters
185 sso
= self
.get_argument("sso")
186 sig
= self
.get_argument("sig")
190 params
= self
.accounts
.decode_discourse_payload(sso
, sig
)
192 # Raise bad request if the signature is invalid
194 raise tornado
.web
.HTTPError(400)
196 # Redirect back if user is already logged in
198 "nonce" : params
.get("nonce"),
199 "external_id" : self
.current_user
.uid
,
202 "email" : self
.current_user
.email
,
203 "require_activation" : "false",
205 # More details about the user
206 "username" : self
.current_user
.uid
,
207 "name" : "%s" % self
.current_user
,
208 "bio" : self
.current_user
.description
or "",
211 "avatar_url" : self
.current_user
.avatar_url(absolute
=True),
212 "avatar_force_update" : "true",
214 # Send a welcome message
215 "suppress_welcome_message" : "false",
218 "admin" : "true" if self
.current_user
.is_admin() else "false",
219 "moderator" : "true" if self
.current_user
.is_moderator() else "false",
222 # Format payload and sign it
223 payload
= self
.accounts
.encode_discourse_payload(**args
)
224 signature
= self
.accounts
.sign_discourse_payload(payload
)
226 qs
= urllib
.parse
.urlencode({
232 self
.redirect("%s?%s" % (params
.get("return_sso_url"), qs
))
235 class APICheckUID(base
.APIHandler
):
236 @base.ratelimit(minutes
=1, requests
=100)
238 uid
= self
.get_argument("uid")
244 # Check if the username is syntactically valid
245 elif not self
.backend
.accounts
.uid_is_valid(uid
):
248 # Check if the username is already taken
249 elif self
.backend
.accounts
.uid_exists(uid
):
252 # Username seems to be okay
253 self
.finish({ "result" : result
or "ok" })
256 class APICheckEmail(base
.APIHandler
):
257 @base.ratelimit(minutes
=1, requests
=100)
259 email
= self
.get_argument("email")
265 elif not self
.backend
.accounts
.mail_is_valid(email
):
268 # Check if this email address is blacklisted
269 elif self
.backend
.accounts
.mail_is_blacklisted(email
):
270 result
= "blacklisted"
272 # Check if this email address is already useed
273 elif self
.backend
.accounts
.get_by_mail(email
):
276 self
.finish({ "result" : result
or "ok" })