Store token and callback URI in memory session

This commit is contained in:
Alex Ling 2020-06-07 16:18:34 +00:00
parent 12c3c3f356
commit de690fbf29
7 changed files with 40 additions and 36 deletions

View File

@ -28,6 +28,10 @@ shards:
github: kemalcr/kemal github: kemalcr/kemal
version: 0.26.1 version: 0.26.1
kemal-session:
github: kemalcr/kemal-session
version: 0.12.1
kilt: kilt:
github: jeromegn/kilt github: jeromegn/kilt
version: 0.4.0 version: 0.4.0

View File

@ -15,6 +15,8 @@ license: MIT
dependencies: dependencies:
kemal: kemal:
github: kemalcr/kemal github: kemalcr/kemal
kemal-session:
github: kemalcr/kemal-session
sqlite3: sqlite3:
github: crystal-lang/crystal-sqlite3 github: crystal-lang/crystal-sqlite3
baked_file_system: baked_file_system:

View File

@ -5,6 +5,7 @@ class Config
property port : Int32 = 9000 property port : Int32 = 9000
property base_url : String = "/" property base_url : String = "/"
property session_secret : String = "mango-session-secret"
property library_path : String = File.expand_path "~/mango/library", property library_path : String = File.expand_path "~/mango/library",
home: true home: true
property db_path : String = File.expand_path "~/mango/mango.db", home: true property db_path : String = File.expand_path "~/mango/mango.db", home: true

View File

@ -21,18 +21,14 @@ class AuthHandler < Kemal::Handler
call_next env call_next env
end end
def validate_cookie_token(env) def validate_token(env)
cookie = env.request.cookies.find do |c| token = env.session.string? "token"
c.name == "token-#{Config.current.port}" !token.nil? && @storage.verify_token token
end
!cookie.nil? && @storage.verify_token cookie.value
end end
def validate_cookie_token_admin(env) def validate_token_admin(env)
cookie = env.request.cookies.find do |c| token = env.session.string? "token"
c.name == "token-#{Config.current.port}" !token.nil? && @storage.verify_admin token
end
!cookie.nil? && @storage.verify_admin cookie.value
end end
def validate_auth_header(env) def validate_auth_header(env)
@ -42,7 +38,7 @@ class AuthHandler < Kemal::Handler
token = verify_user value token = verify_user value
return false if token.nil? return false if token.nil?
set_token_cookie env, token env.session.string "token", token
return true return true
end end
end end
@ -57,7 +53,7 @@ class AuthHandler < Kemal::Handler
end end
def handle_opds_auth(env) def handle_opds_auth(env)
if validate_cookie_token(env) || validate_auth_header(env) if validate_token(env) || validate_auth_header(env)
call_next env call_next env
else else
env.response.status_code = 401 env.response.status_code = 401
@ -69,12 +65,13 @@ class AuthHandler < Kemal::Handler
def handle_auth(env) def handle_auth(env)
return call_next(env) if request_path_startswith env, ["/login", "/logout"] return call_next(env) if request_path_startswith env, ["/login", "/logout"]
unless validate_cookie_token env unless validate_token env
env.session.string "callback", env.request.path
return redirect env, "/login" return redirect env, "/login"
end end
if request_path_startswith env, ["/admin", "/api/admin", "/download"] if request_path_startswith env, ["/admin", "/api/admin", "/download"]
unless validate_cookie_token_admin env unless validate_token_admin env
env.response.status_code = 403 env.response.status_code = 403
end end
end end

View File

@ -9,10 +9,7 @@ class MainRouter < Router
get "/logout" do |env| get "/logout" do |env|
begin begin
cookie = env.request.cookies.find do |c| env.session.delete_string "token"
c.name == "token-#{Config.current.port}"
end.not_nil!
@context.storage.logout cookie.value
rescue e rescue e
@context.error "Error when attempting to log out: #{e}" @context.error "Error when attempting to log out: #{e}"
ensure ensure
@ -26,8 +23,15 @@ class MainRouter < Router
password = env.params.body["password"] password = env.params.body["password"]
token = @context.storage.verify_user(username, password).not_nil! token = @context.storage.verify_user(username, password).not_nil!
set_token_cookie env, token env.session.string "token", token
redirect env, "/"
callback = env.session.string? "callback"
if callback
env.session.delete_string "callback"
redirect env, callback
else
redirect env, "/"
end
rescue rescue
redirect env, "/login" redirect env, "/login"
end end

View File

@ -1,4 +1,5 @@
require "kemal" require "kemal"
require "kemal-session"
require "./library" require "./library"
require "./handlers/*" require "./handlers/*"
require "./util" require "./util"
@ -65,6 +66,13 @@ class Server
serve_static false serve_static false
add_handler StaticHandler.new add_handler StaticHandler.new
{% end %} {% end %}
Kemal::Session.config do |c|
c.timeout = 365.days
c.secret = Config.current.session_secret
c.cookie_name = "mango-sessid-#{Config.current.port}"
c.path = Config.current.base_url
end
end end
def start def start

View File

@ -6,12 +6,9 @@ UPLOAD_URL_PREFIX = "/uploads"
macro layout(name) macro layout(name)
base_url = Config.current.base_url base_url = Config.current.base_url
begin begin
cookie = env.request.cookies.find do |c|
c.name == "token-#{Config.current.port}"
end
is_admin = false is_admin = false
unless cookie.nil? if token = env.session.string? "token"
is_admin = @context.storage.verify_admin cookie.value is_admin = @context.storage.verify_admin token
end end
render "src/views/#{{{name}}}.ecr", "src/views/layout.ecr" render "src/views/#{{{name}}}.ecr", "src/views/layout.ecr"
rescue e rescue e
@ -28,10 +25,8 @@ end
macro get_username(env) macro get_username(env)
# if the request gets here, it has gone through the auth handler, and # if the request gets here, it has gone through the auth handler, and
# we can be sure that a valid token exists, so we can use not_nil! here # we can be sure that a valid token exists, so we can use not_nil! here
cookie = {{env}}.request.cookies.find do |c| token = env.session.string "token"
c.name == "token-#{Config.current.port}" (@context.storage.verify_token token).not_nil!
end.not_nil!
(@context.storage.verify_token cookie.value).not_nil!
end end
def send_json(env, json) def send_json(env, json)
@ -137,13 +132,6 @@ macro render_xml(path)
send_file env, ECR.render({{path}}).to_slice, "application/xml" send_file env, ECR.render({{path}}).to_slice, "application/xml"
end end
def set_token_cookie(env, token)
cookie = HTTP::Cookie.new "token-#{Config.current.port}", token
cookie.path = Config.current.base_url
cookie.expires = Time.local.shift years: 1
env.response.cookies << cookie
end
macro render_component(filename) macro render_component(filename)
render "src/views/components/#{{{filename}}}.ecr" render "src/views/components/#{{{filename}}}.ecr"
end end