diff --git a/app/assets/stylesheets/mobile/settings.scss b/app/assets/stylesheets/mobile/settings.scss index 9b614aa6601a744109d9650228edc130a15a84cc..45b7c633e9e30d2f5b8083f73c0f2318c244b6fe 100644 --- a/app/assets/stylesheets/mobile/settings.scss +++ b/app/assets/stylesheets/mobile/settings.scss @@ -30,35 +30,6 @@ } } -.applications-page { - .applications-explenation { - margin-bottom: 15px; - } - - .application-img { - margin: 9px 0; - float: left; - width: 60px; - max-height: 60px; - text-align: center; - - [class^="entypo-"] { - font-size: 60px; - height: 60px; - margin: 0; - padding: 0; - width: 100%; - &::before { - position: relative; - top: -15px; - } - } - } - - .application-authorizations { - width: calc(100% - 60px); - padding: 0 0 15px 15px; - display: inline-block; - float: right; - } +.applications-page .applications-explanation { + margin-bottom: 15px; } diff --git a/app/assets/stylesheets/user_applications.scss b/app/assets/stylesheets/user_applications.scss index c99ed36729bbdce73d5964cbf32ab56e22f78df3..e3cb694364464acf5a534fc521d1def49280da10 100644 --- a/app/assets/stylesheets/user_applications.scss +++ b/app/assets/stylesheets/user_applications.scss @@ -1,32 +1,28 @@ -.applications-page { - .applications-explenation { - margin-bottom: 15px; - } - - .application-img { - margin: 9px 0; - float: left; - width: 60px; - max-height: 60px; - text-align: center; +.application-img { + margin: 9px 0; + float: left; + width: 60px; + max-height: 60px; + text-align: center; - [class^="entypo-"] { - font-size: 60px; - height: 60px; - margin: 0; - padding: 0; - width: 100%; - &::before { - position: relative; - top: -15px; - } + [class^="entypo-"] { + font-size: 60px; + height: 60px; + margin: 0; + padding: 0; + width: 100%; + &::before { + position: relative; + top: -15px; } } +} - .application-authorizations { - width: calc(100% - 60px); - padding: 0 0 15px 15px; - display: inline-block; - float: right; - } +.application-authorizations { + width: calc(100% - 60px); + padding: 0 0 15px 15px; + display: inline-block; + float: right; } + +.user-consent { margin-top: 20px; } diff --git a/app/controllers/api/openid_connect/authorizations_controller.rb b/app/controllers/api/openid_connect/authorizations_controller.rb index de1aed1926e13aa1de8a2e84106b75feef03a514..09d479f7427769f3a9a8bde5648d7a96fad5f29a 100644 --- a/app/controllers/api/openid_connect/authorizations_controller.rb +++ b/app/controllers/api/openid_connect/authorizations_controller.rb @@ -32,7 +32,7 @@ module Api else flash[:error] = I18n.t("api.openid_connect.authorizations.destroy.fail", id: params[:id]) end - redirect_to user_applications_url + redirect_to api_openid_connect_user_applications_url end private @@ -107,6 +107,13 @@ module Api endpoint.redirect_uri, endpoint.scopes, endpoint.request_object ] save_request_parameters + + @app = { + name: @o_auth_application.client_name, + image: @o_auth_application.image_uri, + authorizations: @scopes + } + render :new end diff --git a/app/controllers/api/openid_connect/user_applications_controller.rb b/app/controllers/api/openid_connect/user_applications_controller.rb new file mode 100644 index 0000000000000000000000000000000000000000..f25603a52c0e8851ad324445abf072a2eb1cd562 --- /dev/null +++ b/app/controllers/api/openid_connect/user_applications_controller.rb @@ -0,0 +1,11 @@ +module Api + module OpenidConnect + class UserApplicationsController < ApplicationController + before_action :authenticate_user! + + def index + @user_apps = UserApplicationsPresenter.new current_user + end + end + end +end diff --git a/app/controllers/user_applications_controller.rb b/app/controllers/user_applications_controller.rb deleted file mode 100644 index 35741d02b79ff28866c7d97aa47f265ce453a3ee..0000000000000000000000000000000000000000 --- a/app/controllers/user_applications_controller.rb +++ /dev/null @@ -1,9 +0,0 @@ -class UserApplicationsController < ApplicationController - before_action :authenticate_user! - - def index - respond_to do |format| - format.all { @user_apps = UserApplicationsPresenter.new current_user } - end - end -end diff --git a/app/models/api/openid_connect/authorization.rb b/app/models/api/openid_connect/authorization.rb index 32e0d52e37ebd1efc1cbdfaa26ac1af3c232bb78..2cdfb1e6d641a0a188c45a6c1922779ce0137bfe 100644 --- a/app/models/api/openid_connect/authorization.rb +++ b/app/models/api/openid_connect/authorization.rb @@ -21,10 +21,11 @@ module Api self.refresh_token = SecureRandom.hex(32) end + def validate_scope_names return unless scopes scopes.each do |scope| - errors.add(:scope, "is not a valid scope name") unless %w(openid read write).include? scope + errors.add(:scope, "is not a valid scope name") unless scopes.include? scope end end @@ -56,9 +57,13 @@ module Api def self.find_by_refresh_token(client_id, refresh_token) Api::OpenidConnect::Authorization.joins(:o_auth_application).find_by( - o_auth_applications: {client_id: client_id}, refresh_token: refresh_token) + o_auth_applications: {client_id: client_id}, refresh_token: refresh_token) end + def self.scopes + %w(openid read write) + end + def self.use_code(code) return unless code find_by(code: code).tap do |auth| diff --git a/app/views/api/openid_connect/authorizations/_form.haml b/app/views/api/openid_connect/authorizations/_form.haml deleted file mode 100644 index 0e1662d1208b937920cb8100ba4d3de917e63b6d..0000000000000000000000000000000000000000 --- a/app/views/api/openid_connect/authorizations/_form.haml +++ /dev/null @@ -1,7 +0,0 @@ -= form_tag api_openid_connect_authorizations_path, class: action do - - if action == :approve - = submit_tag t(".approve") - = hidden_field_tag :approve, true - - else - = submit_tag t(".deny") - = hidden_field_tag :approve, false diff --git a/app/views/api/openid_connect/authorizations/_grants_list.haml b/app/views/api/openid_connect/authorizations/_grants_list.haml new file mode 100644 index 0000000000000000000000000000000000000000..0223043037d8f43d311957d1c87bc321d3dc1dc2 --- /dev/null +++ b/app/views/api/openid_connect/authorizations/_grants_list.haml @@ -0,0 +1,16 @@ +.application-img + - if app[:image] + = image_tag app[:image], class: "img-responsive" + - else + %i.entypo-browser +.application-authorizations + - if app[:authorizations].count > 0 + %h4=t("api.openid_connect.authorizations.new.access", name: app[:name]) + %ul + - app[:authorizations].each do |authorization| + %li + %b= t("api.openid_connect.scopes.#{authorization}.name") + %p= t("api.openid_connect.scopes.#{authorization}.description") + - else + .well + =t("api.openid_connect.authorizations.new.no_requirement", name: app[:name]) diff --git a/app/views/api/openid_connect/authorizations/new.html.haml b/app/views/api/openid_connect/authorizations/new.html.haml index 001b066b9099eea3761d21e868f26420931ffd7c..4443cba3b3090a855701a79baaa5d8b1b3568905 100644 --- a/app/views/api/openid_connect/authorizations/new.html.haml +++ b/app/views/api/openid_connect/authorizations/new.html.haml @@ -1,12 +1,13 @@ -%h2= @o_auth_application.client_name -%p= t(".redirection_message", redirect_uri: @redirect_uri) -%ul - - @scopes.each do |scope| - %li= scope - - if @request_object - %li= t(".requested_objects") - %ul - %pre= JSON.pretty_generate @request_object.as_json +.user-consent.col-md-6.col-md-offset-1 + %ul.list-group + %li.list-group-item.authorized-application + = render "grants_list", app: @app -= render 'api/openid_connect/authorizations/form', action: :approve -= render 'api/openid_connect/authorizations/form', action: :deny + .clearfix + = form_tag api_openid_connect_authorizations_path, class: "pull-right" do + %span + = submit_tag t(".deny"), class: "btn btn-danger" + = hidden_field_tag :deny, false + %span + = submit_tag t(".approve"), class: "btn btn-primary" + = hidden_field_tag :approve, true diff --git a/app/views/api/openid_connect/user_applications/_add_remove_applications.haml b/app/views/api/openid_connect/user_applications/_add_remove_applications.haml new file mode 100644 index 0000000000000000000000000000000000000000..28afb902117e02ef26603e6dcab23d78d947c076 --- /dev/null +++ b/app/views/api/openid_connect/user_applications/_add_remove_applications.haml @@ -0,0 +1,14 @@ +- if @user_apps.applications? + %ul.list-group + - @user_apps.user_applications.each do |app| + %li.list-group-item.authorized-application + = render "grants_list", app: app + = form_for "application", url: "#{api_openid_connect_authorizations_path}/#{app[:id]}", + html: { method: :delete, class: "form-horizontal"} do |f| + .clearfix= f.submit t("api.openid_connect.user_applications.revoke_autorization"), + class: "btn btn-danger pull-right app-revoke" + +- else + .well + %h4 + = t("api.openid_connect.user_applications.no_applications") diff --git a/app/views/api/openid_connect/user_applications/_grants_list.haml b/app/views/api/openid_connect/user_applications/_grants_list.haml new file mode 100644 index 0000000000000000000000000000000000000000..e2c67b8ffc4097480d3177fe137285bb2ef78132 --- /dev/null +++ b/app/views/api/openid_connect/user_applications/_grants_list.haml @@ -0,0 +1,16 @@ +.application-img + - if app[:image] + = image_tag app[:image], class: "img-responsive" + - else + %i.entypo-browser +.application-authorizations + - if app[:authorizations].count > 0 + %h4=t("api.openid_connect.user_applications.index.access", name: app[:name]) + %ul + - app[:authorizations].each do |authorization| + %li + %b= t("api.openid_connect.scopes.#{authorization}.name") + %p= t("api.openid_connect.scopes.#{authorization}.description") + - else + .well + =t("api.openid_connect.user_applications.index.no_requirement",name: app[:name]) diff --git a/app/views/user_applications/index.html.haml b/app/views/api/openid_connect/user_applications/index.html.haml similarity index 100% rename from app/views/user_applications/index.html.haml rename to app/views/api/openid_connect/user_applications/index.html.haml diff --git a/app/views/api/openid_connect/user_applications/index.mobile.haml b/app/views/api/openid_connect/user_applications/index.mobile.haml new file mode 100644 index 0000000000000000000000000000000000000000..da89efde1bc0dc4e1841c25c7b8782b331b1d5d9 --- /dev/null +++ b/app/views/api/openid_connect/user_applications/index.mobile.haml @@ -0,0 +1,13 @@ +.settings_container.applications-page + - content_for :page_title do + = t(".edit_applications") + + = render "shared/settings_nav" + + .container-fluid + .row + .col-md-12.applications-explanation + = t(".applications_explanation") + .col-md-12 + = render "add_remove_applications" + diff --git a/app/views/shared/_settings_nav.haml b/app/views/shared/_settings_nav.haml index 8bd78cc53f7390984f338e54a255d489625c1eae..ceba4baa040cea0343b9c4056e7cff42bbc80fef 100644 --- a/app/views/shared/_settings_nav.haml +++ b/app/views/shared/_settings_nav.haml @@ -6,4 +6,5 @@ %li{class: current_page?(edit_user_path) && "active"}= link_to t("account"), edit_user_path %li{class: current_page?(privacy_settings_path) && "active"}= link_to t("privacy"), privacy_settings_path %li{class: current_page?(services_path) && "active"}= link_to t("_services"), services_path - %li{class: current_page?(user_applications_path) && 'active'}= link_to t("_applications"), user_applications_path + %li{class: current_page?(api_openid_connect_user_applications_path) && "active"} + = link_to t("_applications"), api_openid_connect_user_applications_path diff --git a/app/views/shared/_settings_nav.mobile.haml b/app/views/shared/_settings_nav.mobile.haml index eff5ef101cdbcd2a4bd96f34ea50aabd57a3667c..a85537dcb11eb09f174ba7ceb5600631825150d5 100644 --- a/app/views/shared/_settings_nav.mobile.haml +++ b/app/views/shared/_settings_nav.mobile.haml @@ -6,4 +6,4 @@ %li= link_to_unless_current t('account'), edit_user_path %li= link_to_unless_current t('privacy'), privacy_settings_path %li= link_to_unless_current t('_services'), services_path - %li= link_to_unless_current t('_applications'), user_applications_path + %li= link_to_unless_current t('_applications'), api_openid_connect_user_applications_path diff --git a/app/views/user_applications/_add_remove_applications.haml b/app/views/user_applications/_add_remove_applications.haml deleted file mode 100644 index ed50dba8c086d9555a64b20e35811660d06ec459..0000000000000000000000000000000000000000 --- a/app/views/user_applications/_add_remove_applications.haml +++ /dev/null @@ -1,28 +0,0 @@ -- if @user_apps.applications? - %ul.list-group - - @user_apps.user_applications.each do |app| - %li.list-group-item.authorized-application - .application-img - - if app[:image] - = image_tag app[:image], class: "img-responsive" - - else - %i.entypo-browser - .application-authorizations - - if app[:authorizations].count > 0 - %h4=t("user_applications.index.access", name: app[:name]) - %ul - - app[:authorizations].each do |authorization| - %li - %b= t("user_applications.scopes.#{authorization}.name") - %p= t("user_applications.scopes.#{authorization}.description") - - else - .well - =t("user_applications.show.no_requirement") - = form_for "application", url: "#{api_openid_connect_authorizations_path}/#{app[:id]}", - html: { method: :delete, class: "form-horizontal"} do |f| - .clearfix= f.submit t("user_applications.revoke_autorization"), class: "btn btn-danger pull-right app-revoke" - -- else - .well - %h4 - = t("user_applications.no_applications") diff --git a/app/views/user_applications/index.mobile.haml b/app/views/user_applications/index.mobile.haml deleted file mode 100644 index 27d0b6b82a5df38b12dd7605061d180f9743884a..0000000000000000000000000000000000000000 --- a/app/views/user_applications/index.mobile.haml +++ /dev/null @@ -1,13 +0,0 @@ -.settings_container.applications-page - - content_for :page_title do - = t('.edit_applications') - - = render 'shared/settings_nav' - - .container-fluid - .row - .col-md-12.applications-explenation - = t('.applications_explanation') - .col-md-12 - = render 'add_remove_applications' - diff --git a/config/locales/diaspora/en.yml b/config/locales/diaspora/en.yml index b259e19391a62905c1d8a93d5fc8dce729c48919..8186abeac45307d8dd759ac9c9c4f3702d5b6044 100644 --- a/config/locales/diaspora/en.yml +++ b/config/locales/diaspora/en.yml @@ -886,11 +886,35 @@ en: authorizations: new: redirection_message: "Are you sure you want to give access to %{redirect_uri}?" - form: + access: "%{name} requires access to:" + no_requirement: "%{name} requires no permissions" approve: "Approve" deny: "Deny" destroy: fail: "The attempt to revoke the authorization with ID %{id} has failed" + user_applications: + index: + edit_applications: "Applications" + title: "Authorized applications" + access: "%{name} has access to:" + no_requirement: "%{name} requires no permissions" + applications_explanation: "Here is a list of applications to which you have authorized" + no_applications: "You have no authorized applications" + revoke_autorization: "Revoke" + scopes: + openid: + name: "basic profile" + description: "This allows the application to read your basic profile" + extended: + name: "extended profile" + description: "This allows the application to read your extended profile" + read: + name: "read profile, stream and conversations" + description: "This allows the application to read your stream, your conversations and your complete profile" + write: + name: "send posts, conversations and reactions" + description: "This allows the application to send new posts, write conversations, and send reactions" + people: zero: "No people" one: "1 person" @@ -1476,27 +1500,3 @@ en: disabled: "Not available" open: "Open" closed: "Closed" - - user_applications: - index: - edit_applications: "Applications" - title: "Authorized applications" - access: "%{name} is authorized access to:" - no_requirement: "This application requires no permissions" - applications_explanation: "Here is a list of applications to which you have authorized access" - no_applications: "You have no authorized applications" - revoke_autorization: "Revoke" - scopes: - openid: - name: "basic profile" - description: "This allows the application to read your basic profile" - extended: - name: "extended profile" - description: "This allows the application to read your extended profile" - read: - name: "read profile, stream and conversations" - description: "This allows the application to read your stream, your conversations and your complete profile" - write: - name: "send posts, conversations and reactions" - description: "This allows the application to send new posts, write conversations, and send reactions" - diff --git a/config/routes.rb b/config/routes.rb index 79e585e97d1961af02eeec180443bf2a1351d779..e4ae8ef8a806b47d27fc205e7b20b53bcdfaadaf 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -248,14 +248,12 @@ Diaspora::Application.routes.draw do # See http://openid.net/specs/openid-connect-core-1_0.html#AuthResponseValidation resources :authorizations, only: %i(new create destroy) post "authorizations/new", to: "authorizations#new" - + get "user_applications", to: "user_applications#index" get "jwks.json", to: "id_tokens#jwks" - get "user_info", to: "user_info#show" end end get ".well-known/webfinger", to: "api/openid_connect/discovery#webfinger" get ".well-known/openid-configuration", to: "api/openid_connect/discovery#configuration" - get "user_applications", to: "user_applications#index" end diff --git a/features/support/paths.rb b/features/support/paths.rb index 19ada8e409bd23cfd8f54619c4902e8fee4047b0..368d25b7ea17b32a589e28d10ae3e0b7ff58e423 100644 --- a/features/support/paths.rb +++ b/features/support/paths.rb @@ -37,7 +37,7 @@ module NavigationHelpers when /^forgot password page$/ new_user_password_path when /^user applications page$/ - user_applications_path + api_openid_connect_user_applications_path when %r{^"(/.*)"} Regexp.last_match(1) else diff --git a/lib/api/openid_connect/authorization_point/endpoint.rb b/lib/api/openid_connect/authorization_point/endpoint.rb index bfc5d5ea4eaa960420ec527497083400000a261e..c888e828cc87bbb19a2eb565c5c01e4b7d51e248 100644 --- a/lib/api/openid_connect/authorization_point/endpoint.rb +++ b/lib/api/openid_connect/authorization_point/endpoint.rb @@ -10,7 +10,7 @@ module Api @user = user @app = Rack::OAuth2::Server::Authorize.new do |req, res| build_attributes(req, res) - if OAuthApplication.available_response_types.include? Array(req.response_type).map(&:to_s).join(" ") + if OAuthApplication.available_response_types.include? Array(req.response_type).join(" ") handle_response_type(req, res) else req.unsupported_response_type! @@ -46,11 +46,14 @@ module Api def build_scopes(req) @scopes = req.scope.map {|scope| scope.tap do |scope_name| - # TODO: Use enum - req.invalid_scope! "Unknown scope: #{scope_name}" unless %w(openid read write).include? scope_name + req.invalid_scope! "Unknown scope: #{scope_name}" unless scopes.include? scope_name end } end + + def scopes + Api::OpenidConnect::Authorization.scopes + end end end end diff --git a/spec/controllers/api/openid_connect/authorizations_controller_spec.rb b/spec/controllers/api/openid_connect/authorizations_controller_spec.rb index aa4f13a98929821d4ab49d7bc800b97b4132a5f3..7527bacce85ea657844ec1c4c2ea73bd3f09ff86 100644 --- a/spec/controllers/api/openid_connect/authorizations_controller_spec.rb +++ b/spec/controllers/api/openid_connect/authorizations_controller_spec.rb @@ -302,7 +302,7 @@ describe Api::OpenidConnect::AuthorizationsController, type: :controller do context "with non-existent authorization" do it "raises an error" do delete :destroy, id: 123_456_789 - expect(response).to redirect_to(user_applications_url) + expect(response).to redirect_to(api_openid_connect_user_applications_url) expect(flash[:error]).to eq("The attempt to revoke the authorization with ID 123456789 has failed") end end