From 95683717f577347e608ba2fe692c7995d83e5f4d Mon Sep 17 00:00:00 2001 From: Giovanni Sakti Date: Mon, 28 Jan 2019 09:42:15 +0700 Subject: [PATCH 1/6] move api controller base to comply with convention --- .../{api_controller.rb => api/v1/base_controller.rb} | 2 +- app/controllers/api/v1/users_controller.rb | 2 +- spec/controllers/api_controller_spec.rb | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) rename app/controllers/{api_controller.rb => api/v1/base_controller.rb} (93%) mode change 100755 => 100644 diff --git a/app/controllers/api_controller.rb b/app/controllers/api/v1/base_controller.rb old mode 100755 new mode 100644 similarity index 93% rename from app/controllers/api_controller.rb rename to app/controllers/api/v1/base_controller.rb index 1a38c7b0..2ff254d7 --- a/app/controllers/api_controller.rb +++ b/app/controllers/api/v1/base_controller.rb @@ -1,4 +1,4 @@ -class ApiController < ActionController::Base +class ::Api::V1::BaseController < ActionController::Base protect_from_forgery with: :null_session before_action :authenticate_user_from_token! diff --git a/app/controllers/api/v1/users_controller.rb b/app/controllers/api/v1/users_controller.rb index 3811eaed..075dcee1 100755 --- a/app/controllers/api/v1/users_controller.rb +++ b/app/controllers/api/v1/users_controller.rb @@ -1,4 +1,4 @@ -class ::Api::V1::UsersController < ApiController +class ::Api::V1::UsersController < ::Api::V1::BaseController # respond_to :json, only: [:show] def create user = user_params diff --git a/spec/controllers/api_controller_spec.rb b/spec/controllers/api_controller_spec.rb index 894bd03b..8362006d 100644 --- a/spec/controllers/api_controller_spec.rb +++ b/spec/controllers/api_controller_spec.rb @@ -1,8 +1,8 @@ require 'rails_helper' -RSpec.describe ApiController, type: :controller do +RSpec.describe ::Api::V1::BaseController, type: :controller do - controller(ApiController) do + controller(::Api::V1::BaseController) do def index head :ok end From 20bc00e7bca424fe019f45e85b2dd24091901944 Mon Sep 17 00:00:00 2001 From: Giovanni Sakti Date: Mon, 28 Jan 2019 10:23:46 +0700 Subject: [PATCH 2/6] refactor user API because using current_user for this purpose does not comply with convention --- app/controllers/api/v1/users_controller.rb | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/app/controllers/api/v1/users_controller.rb b/app/controllers/api/v1/users_controller.rb index 075dcee1..49fd7dcf 100755 --- a/app/controllers/api/v1/users_controller.rb +++ b/app/controllers/api/v1/users_controller.rb @@ -1,5 +1,6 @@ class ::Api::V1::UsersController < ::Api::V1::BaseController - # respond_to :json, only: [:show] + before_action :set_user, only: [:show, :update] + def create user = user_params if User.add_temp_user user[:name], user[:email] @@ -10,7 +11,6 @@ def create end def show - @user = current_user if @user.present? user_attrs = %w( email uid name active admin home_dir shell public_key user_login_id @@ -25,10 +25,21 @@ def show end def update - @user = current_user render json: { success: @user.update_profile(user_params) } end + private + + def set_user + @user = if params.key?("email") + User.find_by_email(params["email"]) + elsif params.key?("uid") + User.find_by_uid(params["uid"]) + elsif params.key?("username") + User.find_by_user_login_id(params["username"]) + end + end + def user_params if params.key?(:user) params.require(:user).permit(:name, :email, :public_key, :product_name) From a85014aab9df7924fc1b14542730b7b737217e11 Mon Sep 17 00:00:00 2001 From: Giovanni Sakti Date: Mon, 28 Jan 2019 10:38:27 +0700 Subject: [PATCH 3/6] change current_user function to return user representative of a token --- app/controllers/api/v1/base_controller.rb | 21 +++++++------------ app/models/access_token.rb | 7 +++++-- .../{ => api/v1}/api_controller_spec.rb | 0 spec/models/access_token_spec.rb | 8 ++++++- 4 files changed, 20 insertions(+), 16 deletions(-) rename spec/controllers/{ => api/v1}/api_controller_spec.rb (100%) diff --git a/app/controllers/api/v1/base_controller.rb b/app/controllers/api/v1/base_controller.rb index 2ff254d7..faf8cf49 100644 --- a/app/controllers/api/v1/base_controller.rb +++ b/app/controllers/api/v1/base_controller.rb @@ -8,7 +8,15 @@ def authenticate_user_from_token! end end + protected + + def current_user + access_token = AccessToken.find_token(get_token) + return access_token.user + end + private + def get_token if params.key?(:access_token) return params[:access_token] @@ -22,17 +30,4 @@ def get_token def raise_unauthorized head :unauthorized end - - protected - def current_user - user = if params.key?("email") - User.find_by_email(params["email"]) - elsif params.key?("uid") - User.find_by_uid(params["uid"]) - elsif params.key?("username") - User.find_by_user_login_id(params["username"]) - end - raise_unauthorized if user.blank? - return user - end end diff --git a/app/models/access_token.rb b/app/models/access_token.rb index 2e305b0e..e1eeb749 100644 --- a/app/models/access_token.rb +++ b/app/models/access_token.rb @@ -7,9 +7,12 @@ class AccessToken < ApplicationRecord before_save :hash_token! + def self.find_token challenge_token + AccessToken.where(hashed_token: Digest::SHA512.hexdigest(challenge_token)).first + end + def self.valid_token challenge_token - token = AccessToken.where(hashed_token: Digest::SHA512.hexdigest(challenge_token)) - return token.present? + find_token(challenge_token).present? end private diff --git a/spec/controllers/api_controller_spec.rb b/spec/controllers/api/v1/api_controller_spec.rb similarity index 100% rename from spec/controllers/api_controller_spec.rb rename to spec/controllers/api/v1/api_controller_spec.rb diff --git a/spec/models/access_token_spec.rb b/spec/models/access_token_spec.rb index d2599f8a..a512f684 100644 --- a/spec/models/access_token_spec.rb +++ b/spec/models/access_token_spec.rb @@ -17,7 +17,13 @@ @access_token.save! end - describe "self.authenticate" do + describe "self.find_token" do + it "should return access token object if it finds matching token" do + expect(AccessToken.find_token(@access_token.token)).to eq @access_token + end + end + + describe "self.valid_token" do it "should return true if it finds matching token" do expect(AccessToken.valid_token(@access_token.token)).to eq true end From 461d381029716a0f511e37cda90d9e3a29df75df Mon Sep 17 00:00:00 2001 From: Giovanni Sakti Date: Mon, 28 Jan 2019 10:38:55 +0700 Subject: [PATCH 4/6] create group API --- app/controllers/api/v1/groups_controller.rb | 18 ++++++++++ config/routes.rb | 2 ++ .../api/v1/groups_controller_spec.rb | 35 +++++++++++++++++++ 3 files changed, 55 insertions(+) create mode 100755 app/controllers/api/v1/groups_controller.rb create mode 100755 spec/controllers/api/v1/groups_controller_spec.rb diff --git a/app/controllers/api/v1/groups_controller.rb b/app/controllers/api/v1/groups_controller.rb new file mode 100755 index 00000000..f6ff06f1 --- /dev/null +++ b/app/controllers/api/v1/groups_controller.rb @@ -0,0 +1,18 @@ +class ::Api::V1::GroupsController < ::Api::V1::BaseController + def create + if current_user.admin? + @group = Group.new(group_params) + if @group.save + render json: { status: 'created' }, status: :ok + else + render json: { status: 'error' }, status: :unprocessable_entity + end + end + end + + private + + def group_params + params.require(:group).permit(:name) + end +end diff --git a/config/routes.rb b/config/routes.rb index ef914640..657d6464 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -82,6 +82,8 @@ post 'users' => 'users#create', as: 'add_users_api', format: :json get 'users/profile' => 'users#show', format: :json, :constraints => { format: 'json' } post 'users/profile' => 'users#update', format: :json, :constraints => { format: 'json' } + + resources :groups, only: [:create], format: :json end end diff --git a/spec/controllers/api/v1/groups_controller_spec.rb b/spec/controllers/api/v1/groups_controller_spec.rb new file mode 100755 index 00000000..a982056a --- /dev/null +++ b/spec/controllers/api/v1/groups_controller_spec.rb @@ -0,0 +1,35 @@ +require 'rails_helper' + +RSpec.describe ::Api::V1::GroupsController, type: :controller do + let(:valid_attributes) { + {name: 'jumbo'} + } + + before(:each) do + @user = build(:user) + @user.access_token = build(:access_token) + @user.save + @token = @user.access_token.token + end + + describe 'Authenticated' do + describe 'Create Group' do + context 'with valid_attributes' do + it 'should create groups' do + post :create, params: {group: valid_attributes, access_token: @token} + expect(response.status).to eq(200) + group = Group.where(name: valid_attributes[:name]).first + expect(group.blank?).to eq(false) + expect(group.name).to eq(valid_attributes[:name]) + end + end + end + end + + describe 'Unauthenticated' do + it 'gives 401 when access token is invalid' do + post :create, params: {group: valid_attributes, access_token: 'foo'} + expect(response.status).to eq(401) + end + end +end From ecb706a7ed3d47bb93836db85598a5c73833b173 Mon Sep 17 00:00:00 2001 From: Giovanni Sakti Date: Mon, 28 Jan 2019 10:50:45 +0700 Subject: [PATCH 5/6] create VPN API --- app/controllers/api/v1/vpns_controller.rb | 18 ++++++++++ config/routes.rb | 1 + .../api/v1/vpns_controller_spec.rb | 35 +++++++++++++++++++ 3 files changed, 54 insertions(+) create mode 100755 app/controllers/api/v1/vpns_controller.rb create mode 100755 spec/controllers/api/v1/vpns_controller_spec.rb diff --git a/app/controllers/api/v1/vpns_controller.rb b/app/controllers/api/v1/vpns_controller.rb new file mode 100755 index 00000000..be4698fd --- /dev/null +++ b/app/controllers/api/v1/vpns_controller.rb @@ -0,0 +1,18 @@ +class ::Api::V1::VpnsController < ::Api::V1::BaseController + def create + if current_user.admin? + @vpn = Vpn.new(vpn_params) + if @vpn.save + render json: { status: 'created' }, status: :ok + else + render json: { status: 'error' }, status: :unprocessable_entity + end + end + end + + private + + def vpn_params + params.require(:vpn).permit(:name, :host_name, :ip_address) + end +end diff --git a/config/routes.rb b/config/routes.rb index 657d6464..64593138 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -84,6 +84,7 @@ post 'users/profile' => 'users#update', format: :json, :constraints => { format: 'json' } resources :groups, only: [:create], format: :json + resources :vpns, only: [:create], format: :json end end diff --git a/spec/controllers/api/v1/vpns_controller_spec.rb b/spec/controllers/api/v1/vpns_controller_spec.rb new file mode 100755 index 00000000..adbdd606 --- /dev/null +++ b/spec/controllers/api/v1/vpns_controller_spec.rb @@ -0,0 +1,35 @@ +require 'rails_helper' + +RSpec.describe ::Api::V1::VpnsController, type: :controller do + let(:valid_attributes) { + {name: 'jumbo'} + } + + before(:each) do + @user = build(:user) + @user.access_token = build(:access_token) + @user.save + @token = @user.access_token.token + end + + describe 'Authenticated' do + describe 'Create Vpn' do + context 'with valid_attributes' do + it 'should create vpns' do + post :create, params: {vpn: valid_attributes, access_token: @token} + expect(response.status).to eq(200) + vpn = Vpn.where(name: valid_attributes[:name]).first + expect(vpn.blank?).to eq(false) + expect(vpn.name).to eq(valid_attributes[:name]) + end + end + end + end + + describe 'Unauthenticated' do + it 'gives 401 when access token is invalid' do + post :create, params: {vpn: valid_attributes, access_token: 'foo'} + expect(response.status).to eq(401) + end + end +end From 0b8aeeb29d1c28ecf7cf279a67d4b71e51abc875 Mon Sep 17 00:00:00 2001 From: Giovanni Sakti Date: Mon, 28 Jan 2019 11:01:38 +0700 Subject: [PATCH 6/6] add assign group to VPN API --- app/controllers/api/v1/vpns_controller.rb | 14 ++++++++++++++ config/routes.rb | 6 +++++- spec/controllers/api/v1/vpns_controller_spec.rb | 14 ++++++++++++++ 3 files changed, 33 insertions(+), 1 deletion(-) diff --git a/app/controllers/api/v1/vpns_controller.rb b/app/controllers/api/v1/vpns_controller.rb index be4698fd..3c6c42c9 100755 --- a/app/controllers/api/v1/vpns_controller.rb +++ b/app/controllers/api/v1/vpns_controller.rb @@ -1,4 +1,6 @@ class ::Api::V1::VpnsController < ::Api::V1::BaseController + before_action :set_vpn, only: [:assign_group] + def create if current_user.admin? @vpn = Vpn.new(vpn_params) @@ -10,8 +12,20 @@ def create end end + def assign_group + if current_user.admin? + @vpn.groups.delete_all + @vpn.groups << Group.where(id: params[:group_id]).first + render json: { status: 'group assigned' }, status: :ok + end + end + private + def set_vpn + @vpn = Vpn.find(params[:id]) + end + def vpn_params params.require(:vpn).permit(:name, :host_name, :ip_address) end diff --git a/config/routes.rb b/config/routes.rb index 64593138..4f4f13b0 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -84,7 +84,11 @@ post 'users/profile' => 'users#update', format: :json, :constraints => { format: 'json' } resources :groups, only: [:create], format: :json - resources :vpns, only: [:create], format: :json + resources :vpns, only: [:create], format: :json do + member do + post 'assign_group' + end + end end end diff --git a/spec/controllers/api/v1/vpns_controller_spec.rb b/spec/controllers/api/v1/vpns_controller_spec.rb index adbdd606..9981924e 100755 --- a/spec/controllers/api/v1/vpns_controller_spec.rb +++ b/spec/controllers/api/v1/vpns_controller_spec.rb @@ -24,6 +24,20 @@ end end end + + describe 'Assign Group to VPN' do + it 'should replace existing vpn group with new group' do + vpn = create(:vpn) + group_1 = create(:group) + group_2 = create(:group) + vpn.groups << group_1 + vpn.groups << group_2 + group_3 = create(:group) + post :assign_group, params: {access_token: @token, id: vpn.id, group_id: group_3.id} + expect(vpn.groups.count).to eq 1 + expect(vpn.groups.first).to eq group_3 + end + end end describe 'Unauthenticated' do