# frozen_string_literal: true # ------------------------------------------------------------------------------ # ~/lib/j1_auth_manager/auth_manager/.rb # # Provides authentication services based on Warden|OmniAuth # # Product/Info: # https://jekyll-one.com # # Copyright (C) 2019 Juergen Adams # # J1 Template is licensed under the MIT License. # See: https://github.com/jekyll-one/j1_template_mde/blob/master/LICENSE # # ------------------------------------------------------------------------------ # NOTES # # ------------------------------------------------------------------------------ module J1App class AuthManager < Sinatra::Base include J1App::Helpers include J1App::GithubHelpers # ========================================================================== # Sinatra Framework settings # ========================================================================== # NOTE: https://stackoverflow.com/questions/7847536/sinatra-in-facebook-iframe # #set :protection, :except => :frame_options # Check: http://sinatrarb.com/intro.html # #set :static_cache_control, [:public, :max_age => 10] # ========================================================================== # Base App and Warden Framework settings # ========================================================================== j1_web_session = { :authenticated => 'false', :requested_page => '/', :user_name => 'unknown', :users_allowed => 'unknown', :user_id => 'unknown', :provider => 'unknown', :provider_url => '/', :payment_info => 'unknown', :permissions => 'unknown', :writer => 'middleware' } # Enable SSL for the rack session if configured # -------------------------------------------------------------------------- configure :production do require 'rack-ssl-enforcer' use Rack::SslEnforcer if J1App.ssl? end # Set the session cookie used by Rack to track all relevant data # for the authentication service # -------------------------------------------------------------------------- use Rack::Session::Cookie, http_only: true, key: 'j1.app.session', secret: ENV['J1_SESSION_SECRET'] || SecureRandom.hex # ========================================================================== # Warden Framework initialisation # ========================================================================== # Define what (user) data should be put (serialized) into the session # on requests and responses from Rack environment into the warden # environment (env['warden']). # -------------------------------------------------------------------------- Warden::Manager.serialize_into_session do |user| user end Warden::Manager.serialize_from_session do |user| user end # ========================================================================== # OmniAuth|Warden Framework initialisation # ========================================================================== # Set the 'default' authentication strategy and exception handler # (for warden) if the user was not explicitly signed in (signin dialog). # If 'signin' fails, the default exception 'signin_failure' is thrown # (used for all OmniAuth strategies registered). # -------------------------------------------------------------------------- signin_failure = ->(_e) { Rack::Response.new("Can't login", 401).finish } use Warden::Manager do |config| # OmniAuth strategies are name-spaced by 'omni' (see: warden_omniauth.rb) # ------------------------------------------------------------------------ config.default_strategies :"omni_#{J1App.default_provider}" config.failure_app = signin_failure end use OmniAuth::Builder do |config| # Workaround to rescue OmniAuth::Strategies::OAuth2::CallbackError? # for chromium based browsers (e.g. google-chrome) # ------------------------------------------------------------------------ config.on_failure do new_path = '/redirect_requested_page' Rack::Response.new(['302 Moved'], 302, 'Location' => new_path).finish end # Detect and set supported authentication strategies for OmniAuth # ------------------------------------------------------------------------ # Additional (strategy) option skip_extra, default: true # # If true, skips the collection of raw data (extra) to NOT blow # up the session cookie (as it is limited to 4K) skip_extra = true if J1App.active_providers.include? 'patreon' scope = J1App.auth_config['providers']['patreon']['scope'].join(',') data_collection = J1App.auth_config['providers']['patreon']['data_fields'].join(',') skip_extra = false if data_collection =~ /raw/i provider :patreon, ENV['PATREON_CLIENT_ID'], ENV['PATREON_CLIENT_SECRET'], scope: "#{scope}", skip_extra: skip_extra end if J1App.active_providers.include? 'disqus' scope = J1App.auth_config['providers']['disqus']['scope'].join(',') data_collection = J1App.auth_config['providers']['disqus']['data_fields'].join(',') skip_extra = false if data_collection =~ /raw/i provider :disqus, ENV['DISQUS_CLIENT_ID'], ENV['DISQUS_CLIENT_SECRET'], scope: "#{scope}", skip_extra: skip_extra end if J1App.active_providers.include? 'facebook' scope = J1App.auth_config['providers']['facebook']['scope'].join(',') data_collection = J1App.auth_config['providers']['facebook']['data_fields'].join(',') skip_extra = false if data_collection =~ /raw/i provider :facebook, ENV['FACEBOOK_CLIENT_ID'], ENV['FACEBOOK_CLIENT_SECRET'], scope: "#{scope}", skip_extra: skip_extra end if J1App.active_providers.include? 'github' scope = J1App.auth_config['providers']['github']['scope'].join(',') data_collection = J1App.auth_config['providers']['github']['data_fields'].join(',') skip_extra = false if data_collection =~ /raw/i provider :github, ENV['GITHUB_CLIENT_ID'], ENV['GITHUB_CLIENT_SECRET'], scope: "#{scope}", skip_extra: skip_extra end if J1App.active_providers.include? 'twitter' scope = J1App.auth_config['providers']['twitter']['scope'].join(',') data_collection = J1App.auth_config['providers']['twitter']['data_fields'].join(',') skip_extra = false if data_collection =~ /raw/i provider :twitter, ENV['TWITTER_CLIENT_ID'], ENV['TWITTER_CLIENT_SECRET'], scope: "#{scope}", skip_extra: skip_extra end end # Set the (internal) endpoint if a user is successfully authenticated # -------------------------------------------------------------------------- use J1WardenOmniAuth do |config| config.redirect_after_callback = '/redirect_after_callback' end # Add the internal logger from Rack to the middleware's of the stack # -------------------------------------------------------------------------- use Rack::Logger # Load user profiles, permissions, conditions and strategies # -------------------------------------------------------------------------- providers = J1App.auth_config['providers'] permissions = J1App.permissions # ========================================================================== # Sinatra (before) FILTER to preprocess all page requests # ========================================================================== # Prepare root (index) page for app detection # before '/' do log_info! "RootPage", "PrepareCookie", 'j1.web.session' #logger.info "ROOT PAGE: Prepare J1 web session data" # read existing/current cookie 'j1.web.session' to update all data # of j1_web_session (hash) otherwise set initial data # ------------------------------------------------------------------------ unless env['HTTP_COOKIE'] == nil if env['HTTP_COOKIE'].include? 'j1.web.session' session_encoded = request.cookies['j1.web.session'] session_decoded = Base64.decode64(session_encoded) j1_web_session = JSON.parse(session_decoded) end else requested_page = env['REQUEST_URI'] j1_web_session['requested_page'] = "#{env['REQUEST_URI']}" end # Create|Initialize the J1 web session cookie # ------------------------------------------------------------------------ if warden.authenticated? log_info! "RootPage", 'UpdateCookie', 'Set current user data' user = warden.user log_info! "RootPage", 'AuthCheck', 'User detected as signed in', "#{user[:provider]}" j1_web_session['authenticated'] = 'true' j1_web_session['requested_page'] = '/' j1_web_session['users_allowed'] = providers["#{user[:provider]}"]['users'] j1_web_session['user_name'] = user[:info]['nickname'] j1_web_session['user_id'] = user[:uid] j1_web_session['provider'] = user[:provider] j1_web_session['provider_url'] = providers["#{user[:provider]}"]['home_url'] j1_web_session['permissions'] = providers["#{user[:provider]}"]['permissions'] j1_web_session['payment_info'] = user[:info]['payment_info']['attributes'] unless user[:info]['payment_info'].nil? else log_info! "RootPage", 'AuthCheck', 'User detected', 'signed out' j1_web_session['authenticated'] = 'false' j1_web_session['requested_page'] = '/' j1_web_session['users_allowed'] = 'all' j1_web_session['user_name'] = 'unknown' j1_web_session['user_id'] = 'unknown' j1_web_session['payment_info'] = 'unknown' j1_web_session['provider'] = 'unknown' j1_web_session['provider_url'] = 'unknown' j1_web_session['permissions'] = 'unknown' end j1_web_session['writer'] = 'middleware' session_json = j1_web_session.to_json log_info! "RootPage", 'WriteCookie', 'j1.web.session' # "#{session_json}" session_encoded = Base64.encode64(session_json) response.set_cookie( 'j1.web.session', domain: false, value: session_encoded.to_s, path: '/' ) end # Check auth status for content of type "private" or "premium" # -------------------------------------------------------------------------- #before '/*' do #before /\/\w+\/(public|private|premium)/ do before '/(pages|posts)/*' do # read existing/current cookie 'j1.web.session' # to update all data of j1_web_session (hash) # if request.warden.user.respond_to?(:info) # ------------------------------------------------------------------------ if env['HTTP_COOKIE'].include? 'j1.web.session' session_encoded = request.cookies['j1.web.session'] session_decoded = Base64.decode64(session_encoded) j1_web_session = JSON.parse(session_decoded) log_info! 'Authorisation', 'ReadCookie', 'j1.web.session' # "#{session_decoded}" else requested_page = env['REQUEST_URI'] j1_web_session['requested_page'] = "#{env['REQUEST_URI']}" end # Create|Initialize the J1 web session cookie # ------------------------------------------------------------------------ if warden.authenticated? log_info! 'Authorisation', 'UpdateCookie', 'Set current user data' user = warden.user j1_web_session['authenticated'] = 'true' j1_web_session['user_name'] = user[:info]['nickname'] j1_web_session['user_id'] = user[:uid] j1_web_session['provider'] = user[:provider] j1_web_session['provider_url'] = providers["#{user[:provider]}"]['home_url'] j1_web_session['users_allowed'] = providers["#{user[:provider]}"]['users']# j1_web_session['permissions'] = providers["#{user[:provider]}"]['permissions'] j1_web_session['payment_info'] = user[:info]['payment_info']['attributes'] unless user[:info]['payment_info'].nil? j1_web_session['writer'] = 'middleware' session_json = j1_web_session.to_json log_info! 'Authorisation', 'WriteCookie', 'j1.web.session' # "#{session_json}" session_encoded = Base64.encode64(session_json) response.set_cookie( 'j1.web.session', domain: false, value: session_encoded.to_s, path: '/' ) end # User state|content detection for implicit authentication # ------------------------------------------------------------------------ log_info! 'Authorisation', 'CheckConfig', 'Authentication enabled', "false" if authentication_enabled? == false log_info! 'Authorisation', 'CheckConfig', 'Pass for all pages' if authentication_enabled? == false pass if authentication_enabled? == false log_info! 'Authorisation', 'CheckConfig', 'Authentication enabled', "true" log_info! 'Authorisation', 'DetectContent', 'Check for public content' if public_content? log_info! 'Authorisation', 'DetectContent', 'Pass all public content' if public_content? pass if public_content? log_info! 'Authorisation', 'DetectContent', 'Check for protected content' requested_page = env['REQUEST_URI'] requested_page.scan(/(private|premium)/) do |match| category = match[0] log_info! 'Authorisation', 'DetectContent', 'Content detected', "#{category}" if warden.authenticated? log_info! 'Authorisation', 'UpdateCookie', 'Set current user data' user_name = user[:info]['nickname'] log_info! 'Authorisation', 'AuthCheck', 'User detected', "#{user_name}" current_provider = warden.user[:provider] # provider_strategy = strategies["#{default_provider}"] strategy = providers["#{current_provider}"]['strategy'] provider_strategy = :"#{strategy}" j1_web_session['user_name'] = user_name j1_web_session['provider_url'] = providers["#{current_provider}"]['home_url'] j1_web_session['users_allowed'] = providers["#{current_provider}"]['users'] j1_web_session['permissions'] = providers["#{user[:provider]}"]['permissions'] j1_web_session['requested_page'] = requested_page if permissions[:"#{category}"].include? current_provider log_info! 'Authorisation', 'ContentCheck', 'Provider detected', "#{current_provider}" log_info! 'Authorisation', 'ContentCheck', 'Category supported', "yes - #{category}" # Check permissions # log_info! 'Authorisation', 'ConditionCheck', 'Check permissions for provider', "#{current_provider}" conditions = J1App.conditions current_provider if conditions["#{category}"] log_info! 'Authorisation', 'ConditionCheck', 'Conditions detected for', "#{category}" conditions["#{category}"].each do |k, v| case k when 'enabled' log_info! 'Authorisation', 'ConditionCheck', "#{k}", "#{v}" when 'users' log_info! 'Authorisation', 'ConditionCheck', 'users' v.each do |k, v| log_info! 'Authorisation', 'ConditionCheck', "users - #{k}", "#{v}" end when 'payment' log_info! 'Authorisation', 'ConditionCheck', 'payment' v.each do |k, v| case k when 'tiers' log_info! 'Authorisation', 'ConditionCheck', "payment - #{k}", "#{v}" when 'tier' v.each do |k, v| log_info! 'Authorisation', 'ConditionCheck', 'payment - tiers - tier : ' "#{k}", "#{v}" end end end end end end else provider = permissions[:"#{category}"][0] log_info! 'Authorisation', 'ContentCheck', 'Provider detected', "#{current_provider}" log_info! 'Authorisation', 'ContentCheck', 'Category supported', "no - #{category}" log_info! 'Authorisation', 'SignIn', 'Provider', "#{provider}" warden.logout session.clear session_json = j1_web_session.to_json log_info! 'Authorisation', 'WriteCookie', 'j1.web.session' # "#{session_json}" session_encoded = Base64.encode64(session_json) response.set_cookie( 'j1.web.session', domain: false, value: session_encoded.to_s, path: '/' ) log_info! 'Authorisation', 'AuthManager', 'Request for authentication' allowed_users = providers["#{provider}"]['users'].join(',') redirect "/access_protected_content?provider=#{provider}&category=#{category}&page=#{requested_page}&allowed_users=#{allowed_users}" end log_info! 'Authorisation', 'AuthCheck', 'Pass to requested page', "#{requested_page}" pass else log_info! 'Authentication', 'AuthCheck', 'User detected', 'signed out' default_provider = permissions[:"#{category}"][0] log_info! 'Authentication', 'ContentCheck', 'Set default provider', "#{default_provider}" # provider_strategy = strategies["#{default_provider}"] strategy = providers["#{default_provider}"]['strategy'] provider_strategy = :"#{strategy}" log_info! 'Authentication', 'SignIn', 'Default provider detected', "#{default_provider}" log_info! 'Authentication', 'SignIn', 'Set authentication strategy', "#{provider_strategy}" case provider_strategy when :org warden.authenticate! github_organization_authenticate! ENV['GITHUB_ORG_NAME'] logger.info "Hi There, #{j1_web_session[:user_name]}! You have access to the #{params['id']} organization" when :team warden.authenticate! github_team_authenticate! ENV['GITHUB_TEAM_ID'] logger.info "Hi There, #{j1_web_session[:user_name]}! You have access to the #{params['id']} team" when :teams warden.authenticate! github_teams_authenticate! ENV['GITHUB_TEAM_IDS'].split(',') logger.info "Hi There, #{j1_web_session[:user_name]}! You have access to the #{params['id']} team" when :member log_info! 'Authentication', 'SignIn', "Strategy detected", "member" if env['HTTP_COOKIE'].include? 'j1.web.session' session_encoded = request.cookies['j1.web.session'] session_decoded = Base64.decode64(session_encoded) log_info! 'Authentication', 'ReadCookie', 'j1.web.session' # "#{session_decoded}" j1_web_session = JSON.parse(session_decoded) end # Update cookie data # ---------------------------------------------------------------------- log_info! 'Authentication', 'UpdateCookie', 'Set current user data' j1_web_session['provider_url'] = providers["#{default_provider}"]['home_url'] j1_web_session['users_allowed'] = providers["#{default_provider}"]['users'] j1_web_session['permissions'] = providers["#{default_provider}"]['permissions'] j1_web_session['requested_page'] = env['REQUEST_URI'] j1_web_session['writer'] = 'middleware' # write updated J1 session cookie # session_json = j1_web_session.to_json session_encoded = Base64.encode64(session_json) log_info! 'Authentication', 'WriteCookie', 'j1.web.session' # "#{session_json}" response.set_cookie( 'j1.web.session', domain: false, value: session_encoded.to_s, path: '/' ) allowed_users = providers["#{default_provider}"]['users'].join(',') requested_page = env['REQUEST_URI'] log_info! 'Authorisation', 'AuthManager', 'Request for authentication' redirect "/access_protected_content?provider=#{default_provider}&category=#{category}&page=#{requested_page}&allowed_users=#{allowed_users}" else raise J1App::ConfigError end end end end # ========================================================================== # APP|API ENDPOINTS (Sinatra HANDLERS) # ========================================================================== # Authentication ENDPOINT called from the web (auth client) # -------------------------------------------------------------------------- get '/authentication' do # collect (common) GET parameter|s # request = params.fetch('request') provider = params.fetch('provider') if request === 'signin' log_info! 'Authentication', 'RestApi', 'Called for SignIn' # collect (additional) GET parameter|s # ---------------------------------------------------------------------- allowed_users = params.fetch('allowed_users') j1_web_session['users_allowed'] = allowed_users j1_web_session['writer'] = 'middleware' # Write updated J1 session data to cookie # -------------------------------------------------------------------- session_json = j1_web_session.to_json log_info! 'Authentication', 'RestApi', 'Write J1 web session data to cookie' # #{session_json}" session_encoded = Base64.encode64(session_json) response.set_cookie( 'j1.web.session', domain: false, value: session_encoded.to_s, path: '/' ) if warden.authenticated? log_info! 'Authentication', 'RestApi', 'Already signed in', "#{warden.user[:info]['nickname']} " else log_info! 'Authentication', 'RestApi', 'Go for authentication', "#{provider}" # Make (really) sure that old session is cleared before login # -------------------------------------------------------------------- warden.logout session.clear warden.authenticate! :"omni_#{provider}" end log_info! 'Authentication', 'RestApi', 'Requested page', "#{j1_web_session['requested_page']}" redirect j1_web_session['requested_page'] elsif request === 'signout' log_info! 'Authentication', 'RestApi', 'Called for sign out' # collect (additional) GET parameter|s # ---------------------------------------------------------------------- provider_signout = params.fetch('provider_signout') if warden.authenticated? user = warden.user[:info]['nickname'] provider = warden.user[:provider] provider_url = j1_web_session['provider_url'] warden.logout session.clear # Read current J1 web session cookie # -------------------------------------------------------------------- if env['HTTP_COOKIE'].include? 'j1.web.session' session_encoded = env['rack.request.cookie_hash']['j1.web.session'] session_decoded = Base64.decode64(session_encoded) log_info! 'Authentication', 'RestApi', 'Read J1 web session data from cookie' # #{session_decoded}" j1_web_session = JSON.parse(session_decoded) else j1_web_session['requested_page'] = env['REQUEST_URI'] end # Update J1 web session data # -------------------------------------------------------------------- j1_web_session['user_name'] = 'unknown' j1_web_session['user_id'] = 'unknown' j1_web_session['users_allowed'] = 'unknown' j1_web_session['payment_info'] = 'unknown' j1_web_session['provider'] = 'unknown' j1_web_session['provider_url'] = 'unknown' j1_web_session['permissions'] = 'unknown' j1_web_session['authenticated'] = 'false' j1_web_session['writer'] = 'middleware' # Write updated J1 session data to cookie # -------------------------------------------------------------------- session_json = j1_web_session.to_json log_info! 'Authentication', 'RestApi', 'Write J1 web session data to cookie' # #{session_json}" session_encoded = Base64.encode64(session_json) response.set_cookie( 'j1.web.session', domain: false, value: session_encoded.to_s, path: '/' ) if provider_signout === 'true' log_info! 'Authentication', 'RestApi', 'Sign out user', "#{user}" log_info! 'Authentication', 'RestApi', 'Sign out provider', "#{provider}" log_info! 'Authentication', 'RestApi', 'Sign out from', "#{provider}" log_info! 'Authentication', 'RestApi', 'Redirect to provider', "#{provider_url}" redirect "#{provider_url}" else log_info! 'Authentication', 'RestApi', 'Sign out user', "#{user}" log_info! 'Authentication', 'RestApi', 'Sign out provider', "#{provider}" log_info! 'Authentication', 'RestApi', 'Sign out from', "session" log_info! 'Authentication', 'RestApi', 'Redirect to page', "#{j1_web_session['requested_page']}" # If signed out, redirect ONLY for PUBLIC pages # ------------------------------------------------------------------ if redirect_whitelisted?j1_web_session['requested_page'] log_info! 'Authentication', 'RestApi', 'Redirect detetced as', "whitelisted" log_info! 'Authentication', 'RestApi', 'Requested page', "#{j1_web_session['requested_page']}" redirect j1_web_session['requested_page'] else log_info! 'Authentication', 'RestApi', 'Redirect detetced as', "NOT whitelisted" log_info! 'Authentication', 'RestApi', 'Redirect to', "/" redirect '/' end end else # THIS condition should NEVER REACHED because NO logout dialog # (modal) is provided by the auth client if a user isn't signed in. # Kept this alternative for cases something went wrong. # -------------------------------------------------------------------- log_info! 'Authentication', 'RestApi', 'DEAD PATH: Called for sign out', 'NOT signed in' # Read current J1 session cookie # -------------------------------------------------------------------- if env['HTTP_COOKIE'].include? 'j1.web.session' session_encoded = env['rack.request.cookie_hash']['j1.web.session'] session_decoded = Base64.decode64(session_encoded) j1_web_session = JSON.parse(session_decoded) log_info! 'Authentication', 'RestApi', 'DEAD PATH: Read J1 web session data from cookie' # #{session_decoded}" else j1_web_session['requested_page'] = env['REQUEST_URI'] end # Update J1 web session data # -------------------------------------------------------------------- j1_web_session['user_name'] = 'unknown' j1_web_session['user_id'] = 'unknown' j1_web_session['users_allowed'] = 'unknown' j1_web_session['payment_info'] = 'unknown' j1_web_session['provider'] = 'unknown' j1_web_session['provider_url'] = 'unknown' j1_web_session['permissions'] = 'unknown' j1_web_session['authenticated'] = 'false' j1_web_session['writer'] = 'middleware' # Write updated J1 session data to cookie # -------------------------------------------------------------------- session_json = j1_web_session.to_json log_info! 'Authentication', 'RestApi', 'DEAD PATH: Write J1 web session data to cookie' # #{session_json}" session_encoded = Base64.encode64(session_json) response.set_cookie( 'j1.web.session', domain: false, value: session_encoded.to_s, path: '/' ) log_info! 'Authentication', 'RestApi', 'DEAD PATH: Redirect to requested page', "#{j1_web_session['requested_page']}" redirect j1_web_session['requested_page'] end else raise J1App::ConfigError end end # Post-processing ENDPOINT called after a user is authenticated # -------------------------------------------------------------------------- get '/redirect_after_callback' do reward = { :id => 'unknown', :name => 'unknown', :link => 'javascript:void(0)' } campaign = { :id => 'unknown', :link => 'javascript:void(0)' } session_encoded = request.cookies['j1.web.session'] session_decoded = Base64.decode64(session_encoded) j1_web_session = JSON.parse(session_decoded) log_info! 'Authentication', 'Callback', 'Update web session data' # "#{j1_web_session}" user = warden.user user_json = user.to_json if user[:provider] === 'disqus' user[:info][:urls][:site] = "https://disqus.com" user[:info][:urls][:blog] = user[:info]['urls']['profileUrl'] end if user[:provider] === 'github' user[:info][:urls][:site] = user[:info]['urls']['GitHub'] user[:info][:urls][:blog] = user[:info]['urls']['Blog'] end if user[:provider] === 'patreon' reward_url = user[:info]['payment_info']['relationships']['reward']['links']['related'] reward_json = RestClient.get "#{reward_url}", {:content_type => :json, :accept => :json} reward_data = JSON.parse(reward_json) user[:info][:urls][:site] = "https://patreon.com" user[:info][:urls][:blog] = reward_data['included'][0]['attributes']['url'] reward[:id] = reward_data['data']['id'] reward[:name] = reward_data['data']['attributes']['title'] reward[:link] = "https://patreon.com" + reward_data['data']['attributes']['url'] campaign[:id] = reward_data['data']['relationships']['campaign']['data']['id'] campaign[:link] = reward_data['data']['relationships']['campaign']['links']['related'] end user[:extra][:reward] = reward user[:extra][:campaign] = campaign if user.nil? # Collection of session data failed (e.g cookie > 4K) # log_info! 'Authentication', 'Callback', 'Internal error', 'User authentication failed' warden.logout session.clear redirect "/access_denied?provider=unknown&user=unknown&category=unknown" else log_info! 'Authentication', 'Callback', 'Set current user data' j1_web_session['user_name'] = user[:info]['nickname'] j1_web_session['user_id'] = user[:uid] j1_web_session['provider'] = user[:provider] j1_web_session['permissions'] = providers["#{user[:provider]}"]['permissions'] j1_web_session['authenticated'] = 'true' j1_web_session['payment_info'] = user[:info]['payment_info']['attributes'] unless user[:info]['payment_info'].nil? j1_web_session['writer'] = 'middleware' current_user = user[:info]['nickname'] = user[:info]['nickname'] current_provider = user[:provider] j1_web_session['requested_page'].scan(/(private|premium)/) do |match| category = match[0] unless j1_web_session['users_allowed'].include? 'all' unless j1_web_session['users_allowed'].include? "#{current_user}" log_info! 'Authentication', 'Callback', 'User not allowed', "#{current_user}" log_info! 'Authentication', 'Callback', 'Allowed users', "#{j1_web_session['users_allowed']}" warden.logout session.clear log_info! 'Authentication', 'Callback', 'User signed out', "#{current_user}" redirect "/access_denied?provider=#{current_provider}&user=#{current_user}&category=#{category}" end end end end j1_web_session['provider'] = current_provider j1_web_session['users_allowed'] = providers["#{current_provider}"]['users'] if j1_web_session['requested_page'] == '/' category = 'any protected content' unless j1_web_session['users_allowed'].include? 'all' unless j1_web_session['users_allowed'].include? "#{current_user}" log_info! 'Authentication', 'Callback', 'User not allowed', "#{current_user}" log_info! 'Authentication', 'Callback', 'Allowed users', "#{j1_web_session['users_allowed']}" warden.logout session.clear log_info! 'Authentication', 'Callback', 'User signed out', "#{current_user}" redirect "/access_denied?provider=#{current_provider}&user=#{current_user}&category=#{category}" end end end # write updated J1 session data to cookie # session_json = j1_web_session.to_json log_info! 'Authentication', 'Callback', 'Write J1 web session data to cookie' # "#{session_json}" session_encoded = Base64.encode64(session_json) response.set_cookie( 'j1.web.session', domain: false, value: session_encoded.to_s, path: '/' ) # redirect to requested page # log_info! 'Authentication', 'Callback', 'Signed in at provider', "#{user[:provider]}" log_info! 'Authentication', 'Callback', 'Signed in as user', "#{user[:info]['nickname']}" log_info! 'Authentication', 'Callback', 'Requested page', "#{j1_web_session['requested_page']}" redirect j1_web_session['requested_page'] end get '/redirect_requested_page' do log_info! 'Authentication', 'RedirectPage', 'Requested page', "#{j1_web_session['requested_page']}" redirect j1_web_session['requested_page'] end # Status|Info ENDPOINT called from the web to get current state on an user # -------------------------------------------------------------------------- get '/status' do log_info! 'Status', 'RestApi', 'Info request detected' session_encoded = request.cookies['j1.web.session'] session_decoded = Base64.decode64(session_encoded) j1_web_session = JSON.parse(session_decoded) # if request.warden.user.respond_to?(:info) # if warden.authenticated? # user_json = warden.user.to_json user = warden.user[:info]['nickname'] user_id = warden.user[:uid] user_info = warden.user[:info] provider = warden.user[:provider] provider_url = warden.user[:info][:urls][:site] provider_permissions = j1_web_session['permissions'] if provider == 'patreon' user_member = warden.user[:extra][:reward][:name] user_member_url = warden.user[:extra][:reward][:link] else user_member = 'unknown' user_member_url = 'javascript:void(0)' end log_info! 'Status', 'RestApi', 'User detected as signed in', "#{user}" else user = 'unknown' log_info! 'Status', 'RestApi', 'User detected', 'signed out' end # if request.warden.authenticated? # if user != 'unknown' log_info! 'Status', 'RestApi', 'Send data for', 'SIGNED_IN' content_type 'application/json' { user: user, user_id: user_id, provider: provider, provider_url: provider_url, permissions: provider_permissions, membership: user_member, memberurl: user_member_url, status: 'signed in' }.to_json else log_info! 'Status', 'RestApi', 'Send data for', 'SIGNED_OUT' content_type 'application/json' { user: 'unknown', user_id: 'unknown', provider: 'unknown', provider_url: 'javascript:void(0)', permissions: 'unknown', membership: 'unknown', memberurl: 'javascript:void(0)', status: 'signed out' }.to_json end end # access_protected_content ENDPOINT called from the app (auth manager) # -------------------------------------------------------------------------- get '/access_denied' do provider = params.fetch('provider') category = params.fetch('category') user = params.fetch('user') session_encoded = request.cookies['j1.web.session'] session_decoded = Base64.decode64(session_encoded) j1_web_session = JSON.parse(session_decoded) # Update J1 web session data # -------------------------------------------------------------------- j1_web_session['user_name'] = 'unknown' j1_web_session['user_id'] = 'unknown' j1_web_session['users_allowed'] = 'unknown' j1_web_session['payment_info'] = 'unknown' j1_web_session['provider'] = 'unknown' j1_web_session['provider_url'] = 'unknown' j1_web_session['permissions'] = 'unknown' j1_web_session['authenticated'] = 'false' j1_web_session['writer'] = 'middleware' # write updated J1 session data to cookie # log_info! "AccessControl", 'RestApi', 'Exception', 'Access Denied' session_json = j1_web_session.to_json log_info! "AccessControl", 'RestApi', 'Write J1 web session data to cookie' # "#{session_json}" session_encoded = Base64.encode64(session_json) response.set_cookie( 'j1.web.session', domain: false, value: session_encoded.to_s, path: '/' ) route = '/' @route = route @provider = provider @modal = "centralModalInfo" @info_type = "danger" @modal_icon = "account-off" @modal_ok_text = "Ok, understood" @modal_title = "Authentication Manager" @modal_description = "

Access denied



User #{user} from provider #{provider} is not allowed to access #{category} pages." erb :auth_manager_ui end # access_protected_content ENDPOINT called from the app (auth manager) # -------------------------------------------------------------------------- get '/access_protected_content' do provider = params.fetch('provider') allowed_users = params.fetch('allowed_users') page = params.fetch('page') category = params.fetch('category') if warden.authenticated? route = page else route = "/authentication?request=signin&provider=#{provider}&allowed_users=#{allowed_users}" end @provider = provider @route = route @modal = "signInProtectedContent" @modal_icon = "login" @modal_agreed_text = "Yes, please" @modal_disagreed_text = "No, thanks" @modal_title = "Authentication Manager" @modal_image = "/assets/images/master_header/admin-dashboard-bootstrap-1280x600.png" @modal_description = "The page #{page} you requested belongs to #{category} content. You'll be redirected to authenticate with the provider #{provider}. If signed in successfully, you get access to all #{category} pages." erb :auth_manager_ui end get '/iframe' do @website_url = "https://jekyll-one.github.io/" erb :iframe end end end