summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRémy Coutable <remy@rymai.me>2018-01-24 14:44:49 +0000
committerRémy Coutable <remy@rymai.me>2018-01-24 14:44:49 +0000
commitc28ffa1da3aaed0c189a1787a17ed2c944882f09 (patch)
treeee03616501908f9b974a022ed145ac1798747e65
parent09da89e634c197919b129ad0f781c3cec9b93c37 (diff)
parent45b62dfd324318959ff6fa37f9d3f8a1a95b4aa7 (diff)
downloadgitlab-ce-c28ffa1da3aaed0c189a1787a17ed2c944882f09.tar.gz
Merge branch 'PNSalocin/gitlab-ce-24035-api-create-application' into 'master'
Add application create API Closes #24035 See merge request gitlab-org/gitlab-ce!16643
-rw-r--r--changelogs/unreleased/24035-api-create-application.yml4
-rw-r--r--doc/api/applications.md37
-rw-r--r--lib/api/api.rb1
-rw-r--r--lib/api/applications.rb27
-rw-r--r--lib/api/entities.rb10
-rw-r--r--spec/requests/api/applications_spec.rb86
6 files changed, 165 insertions, 0 deletions
diff --git a/changelogs/unreleased/24035-api-create-application.yml b/changelogs/unreleased/24035-api-create-application.yml
new file mode 100644
index 00000000000..c583a020d9d
--- /dev/null
+++ b/changelogs/unreleased/24035-api-create-application.yml
@@ -0,0 +1,4 @@
+---
+title: Add application create API
+merge_request: 8160
+author: Nicolas Merelli @PNSalocin
diff --git a/doc/api/applications.md b/doc/api/applications.md
new file mode 100644
index 00000000000..933867ed0bb
--- /dev/null
+++ b/doc/api/applications.md
@@ -0,0 +1,37 @@
+# Applications API
+
+> [Introduced][ce-8160] in GitLab 10.5
+
+[ce-8160]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/8160
+
+## Create a application
+
+Create a application by posting a JSON payload.
+
+User must be admin to do that.
+
+Returns `200` if the request succeeds.
+
+```
+POST /applications
+```
+
+| Attribute | Type | Required | Description |
+| --------- | ---- | -------- | ----------- |
+| `name` | string | yes | The name of the application |
+| `redirect_uri` | string | yes | The redirect URI of the application |
+| `scopes` | string | yes | The scopes of the application |
+
+```bash
+curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" --data "name=MyApplication&redirect_uri=http://redirect.uri&scopes=" https://gitlab.example.com/api/v3/applications
+```
+
+Example response:
+
+```json
+{
+ "application_id": "5832fc6e14300a0d962240a8144466eef4ee93ef0d218477e55f11cf12fc3737",
+ "secret": "ee1dd64b6adc89cf7e2c23099301ccc2c61b441064e9324d963c46902a85ec34",
+ "callback_url": "http://redirect.uri"
+}
+```
diff --git a/lib/api/api.rb b/lib/api/api.rb
index ae161efb358..f3f64244589 100644
--- a/lib/api/api.rb
+++ b/lib/api/api.rb
@@ -106,6 +106,7 @@ module API
# Keep in alphabetical order
mount ::API::AccessRequests
+ mount ::API::Applications
mount ::API::AwardEmoji
mount ::API::Boards
mount ::API::Branches
diff --git a/lib/api/applications.rb b/lib/api/applications.rb
new file mode 100644
index 00000000000..b122cdefe4e
--- /dev/null
+++ b/lib/api/applications.rb
@@ -0,0 +1,27 @@
+module API
+ # External applications API
+ class Applications < Grape::API
+ before { authenticated_as_admin! }
+
+ resource :applications do
+ desc 'Create a new application' do
+ detail 'This feature was introduced in GitLab 10.5'
+ success Entities::ApplicationWithSecret
+ end
+ params do
+ requires :name, type: String, desc: 'Application name'
+ requires :redirect_uri, type: String, desc: 'Application redirect URI'
+ requires :scopes, type: String, desc: 'Application scopes'
+ end
+ post do
+ application = Doorkeeper::Application.new(declared_params)
+
+ if application.save
+ present application, with: Entities::ApplicationWithSecret
+ else
+ render_validation_error! application
+ end
+ end
+ end
+ end
+end
diff --git a/lib/api/entities.rb b/lib/api/entities.rb
index 3f4b62dc1b2..7b9a80a234b 100644
--- a/lib/api/entities.rb
+++ b/lib/api/entities.rb
@@ -1157,5 +1157,15 @@ module API
pages_domain
end
end
+
+ class Application < Grape::Entity
+ expose :uid, as: :application_id
+ expose :redirect_uri, as: :callback_url
+ end
+
+ # Use with care, this exposes the secret
+ class ApplicationWithSecret < Application
+ expose :secret
+ end
end
end
diff --git a/spec/requests/api/applications_spec.rb b/spec/requests/api/applications_spec.rb
new file mode 100644
index 00000000000..f56bc932f40
--- /dev/null
+++ b/spec/requests/api/applications_spec.rb
@@ -0,0 +1,86 @@
+require 'spec_helper'
+
+describe API::Applications, :api do
+ include ApiHelpers
+
+ let(:admin_user) { create(:user, admin: true) }
+ let(:user) { create(:user, admin: false) }
+
+ describe 'POST /applications' do
+ context 'authenticated and authorized user' do
+ it 'creates and returns an OAuth application' do
+ expect do
+ post api('/applications', admin_user), name: 'application_name', redirect_uri: 'http://application.url', scopes: ''
+ end.to change { Doorkeeper::Application.count }.by 1
+
+ application = Doorkeeper::Application.find_by(name: 'application_name', redirect_uri: 'http://application.url')
+
+ expect(response).to have_http_status 201
+ expect(json_response).to be_a Hash
+ expect(json_response['application_id']).to eq application.uid
+ expect(json_response['secret']).to eq application.secret
+ expect(json_response['callback_url']).to eq application.redirect_uri
+ end
+
+ it 'does not allow creating an application with the wrong redirect_uri format' do
+ expect do
+ post api('/applications', admin_user), name: 'application_name', redirect_uri: 'wrong_url_format', scopes: ''
+ end.not_to change { Doorkeeper::Application.count }
+
+ expect(response).to have_http_status 400
+ expect(json_response).to be_a Hash
+ expect(json_response['message']['redirect_uri'][0]).to eq('must be an absolute URI.')
+ end
+
+ it 'does not allow creating an application without a name' do
+ expect do
+ post api('/applications', admin_user), redirect_uri: 'http://application.url', scopes: ''
+ end.not_to change { Doorkeeper::Application.count }
+
+ expect(response).to have_http_status 400
+ expect(json_response).to be_a Hash
+ expect(json_response['error']).to eq('name is missing')
+ end
+
+ it 'does not allow creating an application without a redirect_uri' do
+ expect do
+ post api('/applications', admin_user), name: 'application_name', scopes: ''
+ end.not_to change { Doorkeeper::Application.count }
+
+ expect(response).to have_http_status 400
+ expect(json_response).to be_a Hash
+ expect(json_response['error']).to eq('redirect_uri is missing')
+ end
+
+ it 'does not allow creating an application without scopes' do
+ expect do
+ post api('/applications', admin_user), name: 'application_name', redirect_uri: 'http://application.url'
+ end.not_to change { Doorkeeper::Application.count }
+
+ expect(response).to have_http_status 400
+ expect(json_response).to be_a Hash
+ expect(json_response['error']).to eq('scopes is missing')
+ end
+ end
+
+ context 'authorized user without authorization' do
+ it 'does not create application' do
+ expect do
+ post api('/applications', user), name: 'application_name', redirect_uri: 'http://application.url', scopes: ''
+ end.not_to change { Doorkeeper::Application.count }
+
+ expect(response).to have_http_status 403
+ end
+ end
+
+ context 'non-authenticated user' do
+ it 'does not create application' do
+ expect do
+ post api('/applications'), name: 'application_name', redirect_uri: 'http://application.url'
+ end.not_to change { Doorkeeper::Application.count }
+
+ expect(response).to have_http_status 401
+ end
+ end
+ end
+end