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



20
21
22
# File 'lib/jsonapi/authorization/default_pundit_authorizer.rb', line 20

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

Instance Attribute Details

#userObject (readonly)

Returns the value of attribute user.



13
14
15
# File 'lib/jsonapi/authorization/default_pundit_authorizer.rb', line 13

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.



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

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



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

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)



29
30
31
# File 'lib/jsonapi/authorization/default_pundit_authorizer.rb', line 29

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



243
244
245
# File 'lib/jsonapi/authorization/default_pundit_authorizer.rb', line 243

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



260
261
262
# File 'lib/jsonapi/authorization/default_pundit_authorizer.rb', line 260

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



134
135
136
# File 'lib/jsonapi/authorization/default_pundit_authorizer.rb', line 134

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



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

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



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

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.



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

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



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

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



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

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



38
39
40
# File 'lib/jsonapi/authorization/default_pundit_authorizer.rb', line 38

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



67
68
69
70
# File 'lib/jsonapi/authorization/default_pundit_authorizer.rb', line 67

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



80
81
82
83
# File 'lib/jsonapi/authorization/default_pundit_authorizer.rb', line 80

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



53
54
55
56
# File 'lib/jsonapi/authorization/default_pundit_authorizer.rb', line 53

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