mirror of
https://github.com/hkalexling/Mango.git
synced 2025-08-03 11:25:29 -04:00
Merge branch 'feature/auth-proxy' into dev
This commit is contained in:
commit
ffd5f4454b
@ -22,6 +22,7 @@ class Config
|
|||||||
property page_margin : Int32 = 30
|
property page_margin : Int32 = 30
|
||||||
property disable_login = false
|
property disable_login = false
|
||||||
property default_username = ""
|
property default_username = ""
|
||||||
|
property auth_proxy_header_name = ""
|
||||||
property mangadex = Hash(String, String | Int32).new
|
property mangadex = Hash(String, String | Int32).new
|
||||||
|
|
||||||
@[YAML::Field(ignore: true)]
|
@[YAML::Field(ignore: true)]
|
||||||
|
@ -15,7 +15,11 @@ class AuthHandler < Kemal::Handler
|
|||||||
env.response.status_code = 401
|
env.response.status_code = 401
|
||||||
env.response.headers["WWW-Authenticate"] = HEADER_LOGIN_REQUIRED
|
env.response.headers["WWW-Authenticate"] = HEADER_LOGIN_REQUIRED
|
||||||
env.response.print AUTH_MESSAGE
|
env.response.print AUTH_MESSAGE
|
||||||
call_next env
|
end
|
||||||
|
|
||||||
|
def require_auth(env)
|
||||||
|
env.session.string "callback", env.request.path
|
||||||
|
redirect env, "/login"
|
||||||
end
|
end
|
||||||
|
|
||||||
def validate_token(env)
|
def validate_token(env)
|
||||||
@ -49,55 +53,50 @@ class AuthHandler < Kemal::Handler
|
|||||||
Storage.default.verify_user username, password
|
Storage.default.verify_user username, password
|
||||||
end
|
end
|
||||||
|
|
||||||
def handle_opds_auth(env)
|
def call(env)
|
||||||
if validate_token(env) || validate_auth_header(env)
|
# Skip all authentication if requesting /login, /logout, or a static file
|
||||||
call_next env
|
|
||||||
else
|
|
||||||
env.response.status_code = 401
|
|
||||||
env.response.headers["WWW-Authenticate"] = HEADER_LOGIN_REQUIRED
|
|
||||||
env.response.print AUTH_MESSAGE
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def handle_auth(env)
|
|
||||||
if request_path_startswith(env, ["/login", "/logout"]) ||
|
if request_path_startswith(env, ["/login", "/logout"]) ||
|
||||||
requesting_static_file env
|
requesting_static_file env
|
||||||
return call_next(env)
|
return call_next(env)
|
||||||
end
|
end
|
||||||
|
|
||||||
unless validate_token(env) || Config.current.disable_login
|
# Check user is logged in
|
||||||
env.session.string "callback", env.request.path
|
if validate_token env
|
||||||
return redirect env, "/login"
|
# Skip if the request has a valid token
|
||||||
|
elsif Config.current.disable_login
|
||||||
|
# Check default username if login is disabled
|
||||||
|
unless Storage.default.username_exists Config.current.default_username
|
||||||
|
Logger.warn "Default username #{Config.current.default_username} " \
|
||||||
|
"does not exist"
|
||||||
|
return require_auth env
|
||||||
|
end
|
||||||
|
elsif !Config.current.auth_proxy_header_name.empty?
|
||||||
|
# Check auth proxy if present
|
||||||
|
username = env.request.headers[Config.current.auth_proxy_header_name]?
|
||||||
|
unless username && Storage.default.username_exists username
|
||||||
|
Logger.warn "Header #{Config.current.auth_proxy_header_name} unset " \
|
||||||
|
"or is not a valid username"
|
||||||
|
return require_auth env
|
||||||
|
end
|
||||||
|
elsif request_path_startswith env, ["/opds"]
|
||||||
|
# Check auth header if requesting an opds page
|
||||||
|
unless validate_auth_header env
|
||||||
|
return require_basic_auth env
|
||||||
|
end
|
||||||
|
else
|
||||||
|
return require_auth env
|
||||||
end
|
end
|
||||||
|
|
||||||
if request_path_startswith env, ["/admin", "/api/admin", "/download"]
|
# Check admin access when requesting an admin page
|
||||||
# The token (if exists) takes precedence over the default user option.
|
if request_path_startswith env, %w(/admin /api/admin /download)
|
||||||
# this is why we check the default username first before checking the
|
unless is_admin? env
|
||||||
# token.
|
|
||||||
should_reject = true
|
|
||||||
if Config.current.disable_login &&
|
|
||||||
Storage.default.username_is_admin Config.current.default_username
|
|
||||||
should_reject = false
|
|
||||||
end
|
|
||||||
if env.session.string? "token"
|
|
||||||
should_reject = !validate_token_admin(env)
|
|
||||||
end
|
|
||||||
if should_reject
|
|
||||||
env.response.status_code = 403
|
env.response.status_code = 403
|
||||||
send_error_page "HTTP 403: You are not authorized to visit " \
|
return send_error_page "HTTP 403: You are not authorized to visit " \
|
||||||
"#{env.request.path}"
|
"#{env.request.path}"
|
||||||
return
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Let the request go through if it passes the above checks
|
||||||
call_next env
|
call_next env
|
||||||
end
|
end
|
||||||
|
|
||||||
def call(env)
|
|
||||||
if request_path_startswith env, ["/opds"]
|
|
||||||
handle_opds_auth env
|
|
||||||
else
|
|
||||||
handle_auth env
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
@ -48,14 +48,6 @@ class Storage
|
|||||||
|
|
||||||
user_count = db.query_one "select count(*) from users", as: Int32
|
user_count = db.query_one "select count(*) from users", as: Int32
|
||||||
init_admin if init_user && user_count == 0
|
init_admin if init_user && user_count == 0
|
||||||
|
|
||||||
# Verifies that the default username in config is valid
|
|
||||||
if Config.current.disable_login
|
|
||||||
username = Config.current.default_username
|
|
||||||
unless username_exists username
|
|
||||||
raise "Default username #{username} does not exist"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
unless @auto_close
|
unless @auto_close
|
||||||
@db = DB.open "sqlite3://#{@path}"
|
@db = DB.open "sqlite3://#{@path}"
|
||||||
|
@ -1,23 +1,23 @@
|
|||||||
# Web related helper functions/macros
|
# Web related helper functions/macros
|
||||||
|
|
||||||
# This macro defines `is_admin` when used
|
def is_admin?(env) : Bool
|
||||||
macro check_admin_access
|
|
||||||
is_admin = false
|
is_admin = false
|
||||||
# The token (if exists) takes precedence over the default user option.
|
if !Config.current.auth_proxy_header_name.empty? ||
|
||||||
# this is why we check the default username first before checking the
|
Config.current.disable_login
|
||||||
# token.
|
is_admin = Storage.default.username_is_admin get_username env
|
||||||
if Config.current.disable_login
|
|
||||||
is_admin = Storage.default.
|
|
||||||
username_is_admin Config.current.default_username
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# The token (if exists) takes precedence over other authentication methods.
|
||||||
if token = env.session.string? "token"
|
if token = env.session.string? "token"
|
||||||
is_admin = Storage.default.verify_admin token
|
is_admin = Storage.default.verify_admin token
|
||||||
end
|
end
|
||||||
|
|
||||||
|
is_admin
|
||||||
end
|
end
|
||||||
|
|
||||||
macro layout(name)
|
macro layout(name)
|
||||||
base_url = Config.current.base_url
|
base_url = Config.current.base_url
|
||||||
check_admin_access
|
is_admin = is_admin? env
|
||||||
begin
|
begin
|
||||||
page = {{name}}
|
page = {{name}}
|
||||||
render "src/views/#{{{name}}}.html.ecr", "src/views/layout.html.ecr"
|
render "src/views/#{{{name}}}.html.ecr", "src/views/layout.html.ecr"
|
||||||
@ -32,7 +32,7 @@ end
|
|||||||
macro send_error_page(msg)
|
macro send_error_page(msg)
|
||||||
message = {{msg}}
|
message = {{msg}}
|
||||||
base_url = Config.current.base_url
|
base_url = Config.current.base_url
|
||||||
check_admin_access
|
is_admin = is_admin? env
|
||||||
page = "Error"
|
page = "Error"
|
||||||
html = render "src/views/message.html.ecr", "src/views/layout.html.ecr"
|
html = render "src/views/message.html.ecr", "src/views/layout.html.ecr"
|
||||||
send_file env, html.to_slice, "text/html"
|
send_file env, html.to_slice, "text/html"
|
||||||
@ -49,6 +49,8 @@ macro get_username(env)
|
|||||||
rescue e
|
rescue e
|
||||||
if Config.current.disable_login
|
if Config.current.disable_login
|
||||||
Config.current.default_username
|
Config.current.default_username
|
||||||
|
elsif (header = Config.current.auth_proxy_header_name) && !header.empty?
|
||||||
|
env.request.headers[header]
|
||||||
else
|
else
|
||||||
raise e
|
raise e
|
||||||
end
|
end
|
||||||
|
Loading…
x
Reference in New Issue
Block a user