main
1# frozen_string_literal: true
2
3module Scim
4 class Controller < ActionController::API
5 include ActionController::HttpAuthentication::Token::ControllerMethods
6 before_action :apply_scim_content_type
7 before_action :ensure_correct_content_type!
8 before_action :authenticate!
9 helper_method :current_user, :scim_type_for
10 rescue_from StandardError do |error|
11 Rails.logger.error(error)
12 render "server_error", status: :server_error
13 end
14 rescue_from ActiveRecord::RecordInvalid, with: :record_invalid
15 rescue_from ActiveModel::ValidationError, with: :record_invalid
16 rescue_from ActiveRecord::RecordNotFound, with: :not_found
17
18 def current_user
19 Current.user
20 end
21
22 def current_user?
23 Current.user?
24 end
25
26 protected
27
28 def not_found
29 render json: {
30 schemas: [Scim::Kit::V2::Messages::ERROR],
31 detail: "Resource #{params[:id]} not found",
32 status: "404",
33 }.to_json, status: :not_found
34 end
35
36 def record_invalid(error)
37 @error = error
38 @model = error.respond_to?(:model) ? error.model : error.record
39 render "record_invalid", status: :bad_request
40 end
41
42 private
43
44 def authenticate!
45 Current.token = authenticate_with_http_token do |token|
46 Token.authenticate(token)
47 end
48 options = { status: :unauthorized, formats: :scim }
49 render "unauthorized", options unless Current.user?
50 end
51
52 def apply_scim_content_type
53 response.headers['Content-Type'] = Mime[:scim].to_s
54 end
55
56 def ensure_correct_content_type!
57 return if acceptable_content_type?
58
59 status = :unsupported_media_type
60 render 'unsupported_media_type', status: status, formats: :scim
61 end
62
63 def acceptable_content_type?
64 [:scim, :json].include?(request&.content_mime_type&.symbol)
65 end
66
67 def scim_type_for(error)
68 case error
69 when ActiveRecord::RecordInvalid
70 errors = error.record.errors.full_messages
71 if errors.count == 1 &&
72 errors[0].end_with?('has already been taken')
73 return 'uniqueness'
74 end
75 end
76 "invalidValue"
77 end
78 end
79end