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. It does not yet support all the available operations — 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



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

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

Instance Attribute Details

#userObject (readonly)

Returns the value of attribute user.



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

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.



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

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



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

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)



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

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



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

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



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

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



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

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



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

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



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

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.



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

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



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

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



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

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



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

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



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

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



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

def show_related_resources(source_record:)
  ::Pundit.authorize(user, source_record, 'show?')
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



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

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