# RuboCops - Documentation # ------------------------------------------------------------------------------ # See: https://rubocop.readthedocs.io/en/latest/ # RuboCops - Disabled Cops # ------------------------------------------------------------------------------ # rubocop:disable Metrics/BlockLength # rubocop:disable Metrics/ClassLength # rubocop:disable Metrics/LineLength # rubocop:disable Style/StringLiterals # rubocop:disable Style/Documentation # rubocop:disable Metrics/BlockNesting # rubocop:disable Layout/ClosingParenthesisIndentation # rubocop:disable Layout/LeadingCommentSpace # rubocop:disable Layout/EmptyLines # rubocop:disable Layout/EmptyLinesAroundBlockBody # rubocop:disable Layout/FirstParameterIndentation # rubocop:disable Layout/CommentIndentation # rubocop:disable Layout/AlignParameters # rubocop:disable Layout/AlignHash # rubocop:disable Layout/TrailingWhitespace # rubocop:disable Layout/IndentHash # rubocop:disable Layout/SpaceAroundOperators # rubocop:disable Layout/ExtraSpacing # rubocop:disable Style/UnlessElse # rubocop:disable Style/HashSyntax # ------------------------------------------------------------------------------ # ~/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 # # ------------------------------------------------------------------------------ # frozen_string_literal: true 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 # -------------------------------------------------------------------------- require 'rack-ssl-enforcer' if J1App.ssl? use Rack::SslEnforcer if J1App.ssl? # 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 = '/post_authentication' 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! "ROOT", "Prepare", 'Web Session' # 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! "ROOT", 'Cookie', 'Update current user data' user = warden.user log_info! "ROOT", '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_status'] = user[:info][:payment_status] else log_info! "ROOT", '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_status'] = '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! "ROOT", 'Cookie', 'Update web session data' # "#{session_json}" session_encoded = Base64.encode64(session_json) response.set_cookie( 'j1.web.session', domain: false, value: session_encoded.to_s, path: '/' ) end # General page detection (page auth pre-flight) # -------------------------------------------------------------------------- before '/(pages|posts)/*' do log_info! 'AuthManager', 'PreFlight', 'Initial checks initiated' # 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! 'PreFlight', 'Cookie', 'Read web session data' # "#{session_decoded}" else requested_page = env['REQUEST_URI'] j1_web_session['requested_page'] = "#{env['REQUEST_URI']}" end # Create|Initialize the J1 web session cookie # ------------------------------------------------------------------------ log_info! 'PreFlight', 'AuthCheck', 'Check authentication status' if warden.authenticated? 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_status'] = user[:info][:payment_status] j1_web_session['writer'] = 'middleware' log_info! 'PreFlight', 'AuthCheck', 'User authenticated', "#{user[:info]['nickname']}" session_json = j1_web_session.to_json log_info! 'PreFlight', 'Cookie', 'Write web session data' # "#{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! 'PreFlight', 'CheckConfig', 'Authentication check', 'disabled' if authentication_enabled? == false log_info! 'PreFlight', 'AuthCheck', 'Pass for all pages' if authentication_enabled? == false pass if authentication_enabled? == false log_info! 'PreFlight', 'CheckConfig', 'Authentication check', 'enabled' log_info! 'PreFlight', 'DetectContent', 'Public content', 'YES' if public_content? log_info! 'PreFlight', 'DetectContent', 'Pass all public content' if public_content? pass if public_content? log_info! 'PreFlight', 'DetectContent', 'Check content type' requested_page = env['REQUEST_URI'] requested_page.scan(/(private|premium)/) do |match| category = match[0] log_info! 'PreFlight', 'DetectContent', 'Content type detected', "#{category}" log_info! 'PreFlight', 'AuthCheck', 'Check authorisation status' if warden.authenticated? user_name = user[:info]['nickname'] log_info! 'PreFlight', '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 log_info! 'PreFlight', 'ContentCheck', 'Check permissions' if permissions[:"#{category}"].include? current_provider log_info! 'PreFlight', 'ContentCheck', 'Provider detected', "#{current_provider}" log_info! 'PreFlight', 'ContentCheck', 'Category detected', "#{category}" log_info! 'PreFlight', 'ContentCheck', 'Category support', 'enabled' # 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', "#{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! 'PreFlight', 'ContentCheck', 'Provider detected', "#{current_provider}" log_info! 'PreFlight', 'ContentCheck', 'Category detected', "#{category}" log_info! 'PreFlight', 'ContentCheck', 'Category supported', 'NO' log_info! 'PreFlight', 'AuthCheck', 'Authorisation failed for user', "#{user_name}" log_info! 'PreFlight', 'SignOut', 'Sign out user', "#{user_name}" warden.logout session.clear session_json = j1_web_session.to_json log_info! 'PreFlight', 'Cookie', 'Write web session data' # "#{session_json}" session_encoded = Base64.encode64(session_json) response.set_cookie( 'j1.web.session', domain: false, value: session_encoded.to_s, path: '/' ) log_info! 'PreFlight', 'Redirect', 'Call API request', 'PageValidate' allowed_users = providers["#{provider}"]['users'].join(',') redirect "/page_validation?provider=#{provider}&category=#{category}&page=#{requested_page}&allowed_users=#{allowed_users}" end log_info! 'PreFlight', 'AuthCheck', 'Pass to requested page', "#{requested_page}" pass else log_info! 'PreFlight', 'AuthCheck', 'User detected', 'signed out' default_provider = permissions[:"#{category}"][0] log_info! 'PreFlight', 'AuthCheck', 'Set default provider', "#{default_provider}" strategy = providers["#{default_provider}"]['strategy'] provider_strategy = :"#{strategy}" log_info! 'PreFlight', 'AuthCheck', 'Start processing provider', "#{default_provider}" log_info! 'PreFlight', 'AuthCheck', '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! 'PreFlight', 'AuthCheck', 'Process authentication strategy' if env['HTTP_COOKIE'].include? 'j1.web.session' session_encoded = request.cookies['j1.web.session'] session_decoded = Base64.decode64(session_encoded) log_info! 'PreFlight', 'Cookie', 'Read web session data' # "#{session_decoded}" j1_web_session = JSON.parse(session_decoded) end # Update cookie 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! 'PreFlight', 'Cookie', 'Write web session data' # "#{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! 'PreFlight', 'Redirect', 'Call API request', 'PageValidate' redirect "/page_validation?provider=#{default_provider}&category=#{category}&page=#{requested_page}&allowed_users=#{allowed_users}" else raise J1App::ConfigError end end end end # ========================================================================== # API ENDPOINTS (Sinatra HANDLERS) # ========================================================================== # ENDPOINT authentication (called from WEB by auth client) # -------------------------------------------------------------------------- get '/authentication' do # collect (common) GET parameter|s # request = params.fetch('request') provider = params.fetch('provider') log_info! 'API', 'Authentication', 'Authentication request received' # SignIn # ------------------------------------------------------------------------ if request === 'signin' log_info! 'Authentication', 'SignIn', 'Called for provider', "#{provider}" # 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', 'Cookie', 'Write web session data' # #{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', 'SignIn', 'User already signed in', "#{warden.user[:info]['nickname']} " else log_info! 'Authentication', 'SignIn', 'Initiate OmniAuth authentication' # Make (really) sure that old session is cleared before login # -------------------------------------------------------------------- warden.logout session.clear warden.authenticate! :"omni_#{provider}" end # SignOut # ------------------------------------------------------------------------ elsif request === 'signout' # collect (additional) GET parameter|s provider_signout = params.fetch('provider_signout') log_info! 'Authentication', 'SignOut', 'Called for provider', #{provider}" if warden.authenticated? user = warden.user[:info]['nickname'] provider = warden.user[:provider] provider_url = j1_web_session['provider_url'] log_info! 'Authentication', 'SignOut', 'Sign out user', "#{user}" 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', 'Cookie', 'Read web session data' # #{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_status'] = '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', 'Cookie', 'Write web session data' # #{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', 'SignOut', 'Sign out user', "#{user}" log_info! 'Authentication', 'SignOut', 'Sign out from', "#{provider}" log_info! 'Authentication', 'Redirect', 'Pass to provider', "#{provider_url}" redirect "#{provider_url}" else log_info! 'Authentication', 'SignOut', 'Sign out user', "#{user}" log_info! 'Authentication', 'SignOut', 'Sign out from', "session" # If signed out, redirect ONLY for PUBLIC pages # ------------------------------------------------------------------ if redirect_whitelisted?j1_web_session['requested_page'] log_info! 'Authentication', 'Redirect', 'Pass to page', "#{j1_web_session['requested_page']}" redirect j1_web_session['requested_page'] else log_info! 'Authentication', 'Redirect', 'Redirect NOT whitelisted' log_info! 'Authentication', 'Redirect', 'Pass to page', "/" 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', 'API', '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', 'Cookie', 'DEAD PATH. Read web session data' # #{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_status'] = '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', 'Cookie', 'DEAD PATH. Write web session data' # #{session_json}" session_encoded = Base64.encode64(session_json) response.set_cookie( 'j1.web.session', domain: false, value: session_encoded.to_s, path: '/' ) log_info! 'Post Authentication', 'Redirect', 'DEAD PATH: Pass to requested page', "#{j1_web_session['requested_page']}" redirect j1_web_session['requested_page'] end else raise J1App::ConfigError end end # END: get '/authentication' # -------------------------------------------------------------------------- # ENDPOINT post_authentication (called after a user is authenticated) # -------------------------------------------------------------------------- get '/post_authentication' do reward = { :id => 'unknown', :name => 'unknown', :link => '#' } campaign = { :id => 'unknown', :link => '#' } log_info! 'API', 'Post Authentication', 'Identification request received' log_info! 'Post Authentication', 'Cookie', 'Read web session data' session_encoded = request.cookies['j1.web.session'] session_decoded = Base64.decode64(session_encoded) j1_web_session = JSON.parse(session_decoded) user = warden.user user_json = user.to_json if user[:provider] === 'disqus' user[:info][:urls][:site] = "https://disqus.com" user[:info][:urls][:home] = user[:info]['urls']['profileUrl'] user[:info][:urls][:blog] = "https://disqus.com/by/juergen_adams/" user[:info][:urls][:member] = user[:info]['urls']['profileUrl'] end if user[:provider] === 'github' user[:info][:urls][:site] = "https://github.com" user[:info][:urls][:home] = user[:info]['urls']['GitHub'] user[:info][:urls][:blog] = "https://github.com/jekyll-one" user[:info][:urls][:member] = user[:info]['urls']['Blog'] end if user[:provider] === 'patreon' user[:info][:urls][:site] = "https://patreon.com" user[:info][:urls][:home] = "https://patreon.com/home" user[:info][:urls][:blog] = "https://patreon.com/jekyll_one" unless user[:info]['payment_info'].empty? 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][:member] = "https://patreon.com" + reward_data['data']['attributes']['url'] user[:info][:payment_status] = user[:info]['payment_info']['attributes']['declined_since'].nil? ? 'true' : 'false' else reward_url = "" reward_json = "" reward_data = "" user[:info][:payment_status] = 'false' end unless reward_data.empty? 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'] else reward[:id] = "" reward[:name] = "no tiers" reward[:link] = "" campaign[:id] = "" campaign[:link] = "" end end user[:extra][:reward] = reward user[:extra][:campaign] = campaign if user.nil? # Collection of session data failed (e.g cookie > 4K) # log_info! 'Post Authentication', 'Identification', 'Internal error', 'Authentication failed' warden.logout session.clear log_info! 'Post Authentication', 'Redirect', 'Pass to error page (access_denied)' description_title = "Access Denied" redirect "/access_denied?provider=unknown&user=unknown&category=unknown&title=#{description_title}" else log_info! 'Post Authentication', 'Identification', 'Authorization successful' log_info! 'Post Authentication', 'Cookie', 'Update web session data' # "#{j1_web_session}" 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_status'] = user[:info][:payment_status] 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| # Set category from requested page # category = match[0] log_info! 'Post Authentication', 'Identification', 'Process content type', "#{category}" # Check if user is allowed to access protected content in GENERAL # log_info! 'Post Authentication', 'Identification', 'Check allowed users' unless j1_web_session['users_allowed'].include? 'all' unless j1_web_session['users_allowed'].include? "#{current_user}" log_info! 'Post Authentication', 'Identification', 'User not allowed', "#{current_user}" log_info! 'Post Authentication', 'Identification', 'Allowed users', "#{j1_web_session['users_allowed']}" log_info! 'Post Authentication', 'Association', 'Logout user from current session', "#{current_user}" warden.logout session.clear log_info! 'Post Authentication', 'Redirect', 'Pass to error page (access_denied)' description_title = "Access Denied" redirect "/access_denied?provider=#{current_provider}&user=#{current_user}&category=#{category}&title=#{description_title}" end end # Check conditions to access protected content (if any) # log_info! 'Post Authentication', 'Identification', 'Check conditions', "#{current_provider}" check_conditions = providers["#{user[:provider]}"]['conditions'][category]['enabled'] if check_conditions if providers["#{user[:provider]}"]['conditions'][category]['users']['whitelist'].nil? category_whitelist = 'all' else category_whitelist = providers["#{user[:provider]}"]['conditions'][category]['users']['whitelist'] end # Check if user is BLACKLISTED # blacklist = providers["#{user[:provider]}"]['conditions'][category]['users']['blacklist'] if blacklist.include? "#{current_user}" log_info! 'Post Authentication', 'Identification', 'Check blacklisting' log_info! 'Post Authentication', 'Identification', 'User blacklisted', "#{current_user}" user[:info][:blacklisted] = 'true' log_info! 'Post Authentication', 'Association', 'Logout user from current session', "#{current_user}" warden.logout session.clear log_info! 'Post Authentication', 'Redirect', 'Pass to error page (access_denied)' description_title = "Access Denied" redirect "/access_denied?provider=#{current_provider}&user=#{current_user}&category=#{category}&title=#{description_title}" end log_info! 'Post Authentication', 'Identification', 'Check whitelisting' if category_whitelisted? category_whitelist, current_user user[:info][:whitelisted] = 'true' reward[:name] = 'whitelisted' log_info! 'Post Authentication', 'Identification', 'User whitelisted', "#{current_user}" log_info! 'Post Authentication', 'Identification', 'Reward set to', 'Whitelisted' else log_info! 'Post Authentication', 'Identification', 'No whitelisting found', "#{current_user}" end log_info! 'Post Authentication', 'Identification', 'Check conditions' unless category_whitelisted? category_whitelist, current_user log_info! 'Post Authentication', 'Identification', 'Check rewards' payment_tiers = providers["#{user[:provider]}"]['conditions'][category]['payment']['activated'] log_info! 'Post Authentication', 'Identification', 'Check rewards', "#{current_user}" if payment_activated? payment_tiers log_info! 'Post Authentication', 'Identification', 'Reward found', "#{reward[:name]}" # Check if any payment exists for that user # log_info! 'Post Authentication', 'Identification', 'Check payment status' if user[:info]['payment_info'].empty? log_info! 'Post Authentication', 'Identification', 'Payment status: NOT AVAILABLE', "#{current_user}" log_info! 'Post Authentication', 'Association', 'Logout user from current session', "#{current_user}" warden.logout session.clear log_info! 'Post Authentication', 'Redirect', 'Pass to error page (access_denied)' description_title = "Access Denied" redirect "/access_denied?provider=#{current_provider}&user=#{current_user}&category=#{category}&title=#{description_title}" end # Check for VALID payments (scope: pledge-to-me) # payment_status = user[:info]['payment_info']['attributes']['declined_since'] unless payment_valid? payment_status log_info! 'Post Authentication', 'Identification', 'Payment status INVALID', "#{current_user}" log_info! 'Post Authentication', 'Association', 'Logout user from current session', "#{current_user}" warden.logout session.clear log_info! 'Post Authentication', 'Redirect', 'Pass to error page (access_denied)' description_title = "Access Denied" redirect "/access_denied?provider=#{current_provider}&user=#{current_user}&category=#{category}&title=#{description_title}" else log_info! 'Post Authentication', 'Identification', 'Payment status VALID', "#{current_user}" end end end # end category_whitelisted end # end check conditions end # end protected content end # end user.nil? # redirect authenticated|validated user to requested page # j1_web_session['provider'] = current_provider j1_web_session['users_allowed'] = providers["#{current_provider}"]['users'] # TODO: Add membership|product specific data for the SideBar # write updated J1 session data to cookie # session_json = j1_web_session.to_json log_info! 'Post Authentication', 'Cookie', 'Write web session data' # "#{session_json}" session_encoded = Base64.encode64(session_json) response.set_cookie( 'j1.web.session', domain: false, value: session_encoded.to_s, path: '/' ) log_info! 'Post Authentication', 'Identification', 'Provider', "#{user[:provider]}" log_info! 'Post Authentication', 'Identification', 'User', "#{user[:info]['nickname']}" log_info! 'Post Authentication', 'Redirect', 'Pass to requested page', "#{j1_web_session['requested_page']}" redirect j1_web_session['requested_page'] end # END: get /post_authentication # -------------------------------------------------------------------------- # ENDPOINT status (called from WEB to get current state of an user) # -------------------------------------------------------------------------- get '/status' do session_encoded = request.cookies['j1.web.session'] session_decoded = Base64.decode64(session_encoded) j1_web_session = JSON.parse(session_decoded) log_info! 'API', 'Status Request', 'Info request received' # if request.warden.user.respond_to?(:info) # if warden.authenticated? user_name = warden.user[:info]['nickname'] user_id = warden.user[:uid] provider = warden.user[:provider] provider_permissions = j1_web_session['permissions'] provider_site_url = warden.user[:info][:urls][:site] provider_home_url = warden.user[:info][:urls][:home] provider_blog_url = warden.user[:info][:urls][:blog] provider_member_url = warden.user[:info][:urls][:member] if provider == 'patreon' provider_membership = warden.user[:extra][:reward][:name] provider_member_url = warden.user[:extra][:reward][:link] else provider_membership = 'unknown' provider_member_url = '#' end log_info! 'API', 'Status Request', 'User detected as signed in', "#{user_name}" else user_name = 'unknown' log_info! 'API', 'Status Request', 'User detected', 'signed out' end # if request.warden.authenticated? # if user_name != 'unknown' log_info! 'API', 'Status Request', 'Send data', 'SIGNED_IN' content_type 'application/json' { user_name: user_name, user_id: user_id, provider: provider, provider_membership: provider_membership, provider_permissions: provider_permissions, provider_site_url: provider_site_url, provider_home_url: provider_home_url, provider_blog_url: provider_blog_url, provider_member_url: provider_member_url, status: 'signed in' }.to_json else log_info! 'API', 'Status Request', 'Send data', 'SIGNED_OUT' content_type 'application/json' { user_name: 'unknown', user_id: 'unknown', provider: 'unknown', provider_membership: 'unknown', provider_permissions: 'unknown', provider_site_url: '#', provider_home_url: '#', provider_blog_url: '#', provider_member_url: '#', status: 'signed out' }.to_json end end # END: get /status # -------------------------------------------------------------------------- # ENDPOINT access_denied (exception, called from the app|auth manager) # -------------------------------------------------------------------------- get '/access_denied' do provider = params.fetch('provider') category = params.fetch('category') user = params.fetch('user') description_title = params.fetch('title') log_info! 'API', 'ExceptionHandler', 'Request received' log_info! 'ExceptionHandler', 'ERROR', 'Access Denied' 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_status'] = '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' log_info! 'ExceptionHandler', 'Cookie', 'Write web session data' # "#{session_json}" # write updated J1 session data to cookie # session_json = j1_web_session.to_json session_encoded = Base64.encode64(session_json) response.set_cookie( 'j1.web.session', domain: false, value: session_encoded.to_s, path: '/' ) log_info! 'ExceptionHandler', 'Redirect', 'Pass to error page', "Access Denied" # Capitalize first char provider = provider.sub(/^./, &:upcase) 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 = "