Class: JSONAPI::Authorization::DefaultPunditAuthorizer

Inherits:
Object
  • Object
show all
Defined in:
lib/jsonapi/authorization/default_pundit_authorizer.rb

Overview

An authorizer is a class responsible for linking JSONAPI operations to your choice of authorization mechanism.

This class uses Pundit for authorization. You can use your own authorizer class instead if you have different needs. See the README.md for configuration information.

Fetching records is the concern of PunditScopedResource which in turn affects which records end up being passed here.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(context:) ⇒ DefaultPunditAuthorizer

Creates a new DefaultPunditAuthorizer instance

Parameters

  • context - The context passed down from the controller layer



22
23
24
# File 'lib/jsonapi/authorization/default_pundit_authorizer.rb', line 22

def initialize(context:)
  @user = JSONAPI::Authorization.configuration.user_context(context)
end

Instance Attribute Details

#userObject (readonly)

Returns the value of attribute user.



15
16
17
# File 'lib/jsonapi/authorization/default_pundit_authorizer.rb', line 15

def user
  @user
end

Instance Method Details

#create_resource(source_class:, related_records_with_context:) ⇒ Object

POST /resources

Parameters

  • source_class - The class of the record to be created

  • related_records_with_context - A has with the association type,

the relationship name, and an Array of new related records.



109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
# File 'lib/jsonapi/authorization/default_pundit_authorizer.rb', line 109

def create_resource(source_class:, related_records_with_context:)
  ::Pundit.authorize(user, source_class, 'create?')
  related_records_with_context.each do |data|
    relation_name = data[:relation_name]
    records = data[:records]
    relationship_method = "create_with_#{relation_name}?"
    policy = ::Pundit.policy(user, source_class)
    if policy.respond_to?(relationship_method)
      unless policy.public_send(relationship_method, records)
        raise ::Pundit::NotAuthorizedError,
              query: relationship_method,
              record: source_class,
              policy: policy
      end
    else
      Array(records).each do |record|
        ::Pundit.authorize(user, record, 'update?')
      end
    end
  end
end

#create_to_many_relationship(source_record:, new_related_records:, relationship_type:) ⇒ Object

POST /resources/:id/relationships/other-resources

A request for adding to a has_many association

Parameters

  • source_record - The record whose relationship is modified

  • new_related_records - The new records to be added to the association

  • relationship_type - The relationship type



167
168
169
170
171
172
173
174
# File 'lib/jsonapi/authorization/default_pundit_authorizer.rb', line 167

def create_to_many_relationship(source_record:, new_related_records:, relationship_type:)
  relationship_method = "add_to_#{relationship_type}?"
  authorize_relationship_operation(
    source_record: source_record,
    relationship_method: relationship_method,
    related_record_or_records: new_related_records
  )
end

#find(source_class:) ⇒ Object

GET /resources

Parameters

  • source_class - The source class (e.g. Article for ArticleResource)



31
32
33
# File 'lib/jsonapi/authorization/default_pundit_authorizer.rb', line 31

def find(source_class:)
  ::Pundit.authorize(user, source_class, 'index?')
end

#include_has_many_resource(source_record:, record_class:) ⇒ Object

Any request including ?include=other-resources

This will be called for each has_many relationship if the include goes deeper than one level until some authorization fails or the include directive has been travelled completely.

We can’t pass all the records of a has_many association here due to performance reasons, so the class is passed instead.

Parameters

  • source_record — The source relationship record, e.g. an Article in

    article.comments check
    
  • record_class - The underlying record class for the relationships

    resource.
    

rubocop:disable Lint/UnusedMethodArgument



245
246
247
# File 'lib/jsonapi/authorization/default_pundit_authorizer.rb', line 245

def include_has_many_resource(source_record:, record_class:)
  ::Pundit.authorize(user, record_class, 'index?')
end

#include_has_one_resource(source_record:, related_record:) ⇒ Object

Any request including ?include=another-resource

This will be called for each has_one relationship if the include goes deeper than one level until some authorization fails or the include directive has been travelled completely.

Parameters

  • source_record — The source relationship record, e.g. an Article in

    article.author check
    
  • related_record - The associated record to return

rubocop:disable Lint/UnusedMethodArgument



262
263
264
# File 'lib/jsonapi/authorization/default_pundit_authorizer.rb', line 262

def include_has_one_resource(source_record:, related_record:)
  ::Pundit.authorize(user, related_record, 'show?')
end

#remove_resource(source_record:) ⇒ Object

DELETE /resources/:id

Parameters

  • source_record - The record to be removed



136
137
138
# File 'lib/jsonapi/authorization/default_pundit_authorizer.rb', line 136

def remove_resource(source_record:)
  ::Pundit.authorize(user, source_record, 'destroy?')
end

#remove_to_many_relationship(source_record:, related_records:, relationship_type:) ⇒ Object

DELETE /resources/:id/relationships/other-resources

A request to disassociate elements of a has_many association

Parameters

  • source_record - The record whose relationship is modified

  • related_records - The records which will be disassociated from source_record

  • relationship_type - The relationship type



204
205
206
207
208
209
210
211
# File 'lib/jsonapi/authorization/default_pundit_authorizer.rb', line 204

def remove_to_many_relationship(source_record:, related_records:, relationship_type:)
  relationship_method = "remove_from_#{relationship_type}?"
  authorize_relationship_operation(
    source_record: source_record,
    relationship_method: relationship_method,
    related_record_or_records: related_records
  )
end

#remove_to_one_relationship(source_record:, relationship_type:) ⇒ Object

DELETE /resources/:id/relationships/another-resource

A request to disassociate a has_one association

Parameters

  • source_record - The record whose relationship is modified

  • relationship_type - The relationship type



221
222
223
224
225
226
227
# File 'lib/jsonapi/authorization/default_pundit_authorizer.rb', line 221

def remove_to_one_relationship(source_record:, relationship_type:)
  relationship_method = "remove_#{relationship_type}?"
  authorize_relationship_operation(
    source_record: source_record,
    relationship_method: relationship_method
  )
end

#replace_fields(source_record:, related_records_with_context:) ⇒ Object

PATCH /resources/:id

Parameters

  • source_record - The record to be modified

  • related_records_with_context - A hash with the association type,

the relationship name, an Array of new related records.



94
95
96
97
98
99
100
# File 'lib/jsonapi/authorization/default_pundit_authorizer.rb', line 94

def replace_fields(source_record:, related_records_with_context:)
  ::Pundit.authorize(user, source_record, 'update?')
  authorize_related_records(
    source_record: source_record,
    related_records_with_context: related_records_with_context
  )
end

#replace_to_many_relationship(source_record:, new_related_records:, relationship_type:) ⇒ Object

PATCH /resources/:id/relationships/other-resources

A replace request for a has_many association

Parameters

  • source_record - The record whose relationship is modified

  • new_related_records - The new records replacing the entire has_many association

  • relationship_type - The relationship type



186
187
188
189
190
191
192
193
# File 'lib/jsonapi/authorization/default_pundit_authorizer.rb', line 186

def replace_to_many_relationship(source_record:, new_related_records:, relationship_type:)
  relationship_method = "replace_#{relationship_type}?"
  authorize_relationship_operation(
    source_record: source_record,
    relationship_method: relationship_method,
    related_record_or_records: new_related_records
  )
end

#replace_to_one_relationship(source_record:, new_related_record:, relationship_type:) ⇒ Object

PATCH /resources/:id/relationships/another-resource

A replace request for a has_one association

Parameters

  • source_record - The record whose relationship is modified

  • new_related_record - The new record replacing the old record

  • relationship_type - The relationship type



149
150
151
152
153
154
155
156
# File 'lib/jsonapi/authorization/default_pundit_authorizer.rb', line 149

def replace_to_one_relationship(source_record:, new_related_record:, relationship_type:)
  relationship_method = "replace_#{relationship_type}?"
  authorize_relationship_operation(
    source_record: source_record,
    relationship_method: relationship_method,
    related_record_or_records: new_related_record
  )
end

#show(source_record:) ⇒ Object

GET /resources/:id

Parameters

  • source_record - The record to show



40
41
42
# File 'lib/jsonapi/authorization/default_pundit_authorizer.rb', line 40

def show(source_record:)
  ::Pundit.authorize(user, source_record, 'show?')
end

GET /resources/:id/another-resource

A query for a record through a has_one association

Parameters

  • source_record - The record whose relationship is queried

  • related_record - The associated record to show or nil if the associated record was not found



69
70
71
72
# File 'lib/jsonapi/authorization/default_pundit_authorizer.rb', line 69

def show_related_resource(source_record:, related_record:)
  ::Pundit.authorize(user, source_record, 'show?')
  ::Pundit.authorize(user, related_record, 'show?') unless related_record.nil?
end

GET /resources/:id/other-resources

A query for records through a has_many association

Parameters

  • source_record - The record whose relationship is queried

  • related_record_class - The associated record class to show



82
83
84
85
# File 'lib/jsonapi/authorization/default_pundit_authorizer.rb', line 82

def show_related_resources(source_record:, related_record_class:)
  ::Pundit.authorize(user, source_record, 'show?')
  ::Pundit.authorize(user, related_record_class, 'index?')
end

#show_relationship(source_record:, related_record:) ⇒ Object

GET /resources/:id/relationships/other-resources GET /resources/:id/relationships/another-resource

A query for a has_one or a has_many association

Parameters

  • source_record - The record whose relationship is queried

  • related_record - The associated has_one record to show or nil if the associated record was not found. For a has_many association, this will always be nil



55
56
57
58
# File 'lib/jsonapi/authorization/default_pundit_authorizer.rb', line 55

def show_relationship(source_record:, related_record:)
  ::Pundit.authorize(user, source_record, 'show?')
  ::Pundit.authorize(user, related_record, 'show?') unless related_record.nil?
end