Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,14 @@ WORKDIR /home/rails/services/app
# Install gems that need compiling first b/c they can take a long time to compile
RUN gem install \
bundler:2.0.2 \
nokogiri:1.10.4 \
ffi:1.11.1 \
grpc:1.23.0 \
nokogiri:1.10.5 \
ffi:1.11.3 \
grpc:1.25.0 \
mini_portile2:2.4.0 \
msgpack:1.3.1 \
pg:1.1.4 \
nio4r:2.5.1 \
puma:4.1.1 \
nio4r:2.5.2 \
puma:4.3.0 \
eventmachine:1.2.7

# NOTE: Copy in a generic Gemfile and the dependent gem's gemspecs so that their dependencies are also installed
Expand Down
2 changes: 1 addition & 1 deletion lib/core/app/controllers/file_fingerprints_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ def index
private

def resources
# @TODO: Add proper filters based on resource class
# TODO: Add proper filters based on resource class
if params.dig(:filter, :model_name)
models.select! { |model| model.model_name.downcase == params[:filter][:model_name].downcase }
end
Expand Down
15 changes: 15 additions & 0 deletions lib/core/app/controllers/policy_actions_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# frozen_string_literal: true

class PolicyActionsController < ApplicationController
def index
render json: json_resources(resource_class: PolicyActionResource, records: resources)
end

private

def resources
return [] unless (json = Settings.dig(:service, :policy_actions))

json.map { |model| PolicyActionResource.new(PolicyAction.new(model), nil) }
end
end
15 changes: 15 additions & 0 deletions lib/core/app/controllers/service_policies_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# frozen_string_literal: true

class ServicePoliciesController < ApplicationController
def index
render json: json_resources(resource_class: ServicePolicyResource, records: resources)
end

private

def resources
return [] unless (json = Settings.dig(:service, :policies))

json.map { |model| ServicePolicyResource.new(ServicePolicy.new(model), nil) }
end
end
2 changes: 1 addition & 1 deletion lib/core/app/models/concerns/ros/tenant_concern.rb
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ def schema_name_from(account_id: nil, id: nil)
end

def account_id_to_schema(account_id)
account_id.to_i.zero? ? 'public' : account_id.to_s.scan(/.{3}/).join('_')
%w[public 0].include?(account_id.to_s) ? 'public' : account_id.to_s.scan(/.{3}/).join('_')
end
end

Expand Down
32 changes: 32 additions & 0 deletions lib/core/app/models/policy_action.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# frozen_string_literal: true

class PolicyAction
include ActiveModel::Model
attr_reader :id, :name, :actions

def initialize(model)
@id = SecureRandom.uuid
@name = model['name']
@actions = model['actions']
end

def readonly?
true
end

def persisted?
false
end

def self.all
new
end

def order
[self] # following order collect is called on the result so return an array with self
end

def count
1 # count is called for meta
end
end
34 changes: 34 additions & 0 deletions lib/core/app/models/service_policy.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# frozen_string_literal: true

class ServicePolicy
include ActiveModel::Model
attr_reader :id, :name, :description, :version, :rules

def initialize(model)
@id = SecureRandom.uuid
@name = model['name']
@description = model['description']
@version = model['version']
@rules = model['rules']
end

def readonly?
true
end

def persisted?
false
end

def self.all
new
end

def order
[self] # following order collect is called on the result so return an array with self
end

def count
1 # count is called for meta
end
end
6 changes: 6 additions & 0 deletions lib/core/app/resources/policy_action_resource.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# frozen_string_literal: true

class PolicyActionResource < JSONAPI::Resource
attributes :name, :actions
paginator :none
end
6 changes: 6 additions & 0 deletions lib/core/app/resources/service_policy_resource.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# frozen_string_literal: true

class ServicePolicyResource < JSONAPI::Resource
attributes :name, :description, :version, :rules
paginator :none
end
2 changes: 2 additions & 0 deletions lib/core/config/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
[{ errors: [{ status: '404', title: 'Not found' }] }.to_json]]
}
jsonapi_resources :tenants
jsonapi_resources :service_policies, only: [:index]
jsonapi_resources :policy_actions, only: [:index]
jsonapi_resources :file_fingerprints, only: [:index]
jsonapi_resources :cloud_event_subjects, only: [:index]
end
16 changes: 16 additions & 0 deletions lib/core/lib/ros/core.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
require 'attr_encrypted'
require 'config'
require 'hashids'
require 'iron_hide'
require 'jsonapi-resources'
require 'jsonapi/authorization'
require 'jwt'
Expand All @@ -20,6 +21,8 @@

require_relative 'api_token_strategy'
require_relative 'dtrace_middleware'
require_relative 'iron_hide/rule'
require_relative 'iron_hide/storage/service_adapter'
require_relative 'jsonapi_authorization/authorizer'
require_relative 'jwt'
require_relative '../migrations'
Expand Down Expand Up @@ -69,6 +72,19 @@ def api_calls_enabled

# By default all services exclude only the Tenant model from schemas
def excluded_models; %w[Tenant] end

def paths; @paths ||= HashWithIndifferentAccess.new(policies: [], policy_actions: []) end

def load_policies
%i[policies policy_actions].each do |type|
Settings.service[type] = Ros.paths[type].each_with_object([]) do |path, ary|
path = path.to_s.end_with?('.json') ? path : "#{path}/*.json"
Dir[path].each { |policy_file| ary << JSON.parse(File.read(policy_file)) }
end.flatten
end
rescue JSON::ParserError
Rails.logger.warn('Error parsing security policies')
end
end

class AccessKey
Expand Down
1 change: 1 addition & 0 deletions lib/core/lib/ros/core/console.rb
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,7 @@ class Reload < Pry::ClassCommand
def process
Ros::Console::Methods.reset_shortcuts
TOPLEVEL_BINDING.eval('self').reload!
Ros.load_policies
Rails.configuration.x.memoized_shortcuts[:ct] = Tenant.find_by(schema_name: Apartment::Tenant.current)
end

Expand Down
10 changes: 10 additions & 0 deletions lib/core/lib/ros/core/engine.rb
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,16 @@ class Engine < ::Rails::Engine
end
end

initializer 'ros_core.initialize_policies' do |_app|
Ros.paths[:policies] << root.join('doc/policies')
Ros.load_policies
IronHide.config do |config|
config.adapter = :service
# config.namespace = Settings.service.policy_name
config.namespace = Settings.service.name
end
end

# Configure ActionMailer (used by Devise) based on our Settings.smtp
initializer 'ros_core.initialize_action_mailer' do |app|
# NOTE: Enabling the smtp is not enough. The service that enables
Expand Down
16 changes: 16 additions & 0 deletions lib/core/lib/ros/healthz_middleware.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# frozen_string_literal: true

module Ros
class HealthzMiddleware
def initialize(app)
@app = app
end

def call(env)
# Respond with 200 to Kubernetes health check
return [200, { 'Content-Type' => 'text/plain' }, ['']] if env.fetch('PATH_INFO') == '/healthz'

@app.call(env)
end
end
end
17 changes: 17 additions & 0 deletions lib/core/lib/ros/iron_hide/rule.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# frozen_string_literal: true

module IronHide
class Rule
def self.find(user, action, resource)
cache = IronHide.configuration.memoizer.new
ns_resource = "#{ApplicationRecord.urn_base}*:*:#{resource.class.name.downcase}"
# ns_resource = resource.class.to_urn
# NOTE: modified to pass the user into the storage adapter
ar = storage.where(user: user, resource: ns_resource, action: action).map do |json|
new(user, resource, json, cache)
end
binding.pry
ar
end
end
end
21 changes: 21 additions & 0 deletions lib/core/lib/ros/iron_hide/storage/service_adapter.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# frozen_string_literal: true

module IronHide
class Storage
class ServiceAdapter < FileAdapter
def initialize; end

def where(opts = {})
keys = opts[:user].attached_policies.keys
policy = Settings.dig(:service, :policies)
json = policy.select { |p| keys.include?(p['name']) }.map { |j| j['rules'] }.flatten
@rules = unfold(json)
# @rules = unfold(opts[:user].attached_policies)
self[opts[:resource]][opts[:action]]
end
end
end
end

# Add adapter class to IronHide::Storage
IronHide::Storage::ADAPTERS.merge!(service: :ServiceAdapter)
11 changes: 0 additions & 11 deletions lib/core/lib/ros/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,5 @@ module Routes
def catch_not_found
match '*path', controller: 'application', action: :not_found, via: :all
end
# def cache(*resources)
# resources.each do |resource|
# get "#{resource}_cache", to: "#{resource}#cache"
# end
# end

# def report(*resources)
# resources.each do |resource|
# get "#{resource}_reports", to: "#{resource}#reports"
# end
# end
end
end
1 change: 1 addition & 0 deletions lib/core/ros-core.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ Gem::Specification.new do |spec|
spec.add_dependency 'aws-sdk-s3'
spec.add_dependency 'config', '1.7.1'
spec.add_dependency 'hashids', '1.0.5'
spec.add_dependency 'iron_hide', '0.4.1'
spec.add_dependency 'grpc', '1.23.0'
spec.add_dependency 'json_schemer', '0.2.6'
spec.add_dependency 'jsonapi-authorization', '3.0.1'
Expand Down
Loading