diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 000000000..35eb1ddfb
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/README.md b/README.md
index b929c9d36..05900ed62 100644
--- a/README.md
+++ b/README.md
@@ -19,6 +19,11 @@ API Umbrella is an open source API management platform for exposing web service
Binary packages are available for [download](https://apiumbrella.io/install/). Follow the quick setup instructions on the download page to begin running API Umbrella.
+## Additional Features
+
+In this repo is hosted one additional feature of API-Umbrella for providing validation using external IdP's.
+The documentation about how to use is available here: [Documentation](./docs/idp-doc.md)
+
## Getting Started
Once you have API Umbrella up and running, there are a variety of things you can do to start using the platform. For a quick tutorial, see [getting started](https://api-umbrella.readthedocs.org/en/latest/getting-started.html).
diff --git a/Vagrantfile b/Vagrantfile
index 507117289..60b6a9d73 100644
--- a/Vagrantfile
+++ b/Vagrantfile
@@ -62,6 +62,7 @@ Vagrant.configure("2") do |config|
end
config.vm.synced_folder "src/api-umbrella/admin-ui", "/vagrant-admin-ui",
+ :nfs => options[:nfs],
:type => "rsync",
:rsync__verbose => true,
:rsync__exclude => [
diff --git a/bin/api-umbrella b/bin/api-umbrella
old mode 100755
new mode 100644
diff --git a/bin/api-umbrella-cli b/bin/api-umbrella-cli
old mode 100755
new mode 100644
diff --git a/bin/api-umbrella-exec b/bin/api-umbrella-exec
old mode 100755
new mode 100644
diff --git a/bin/api-umbrella-geoip-auto-updater b/bin/api-umbrella-geoip-auto-updater
old mode 100755
new mode 100644
diff --git a/bin/api-umbrella-nginx-reloader b/bin/api-umbrella-nginx-reloader
old mode 100755
new mode 100644
diff --git a/bin/docker-compose/make b/bin/docker-compose/make
old mode 100755
new mode 100644
diff --git a/bin/docker-compose/rake b/bin/docker-compose/rake
old mode 100755
new mode 100644
diff --git a/build/package/build_package b/build/package/build_package
old mode 100755
new mode 100644
diff --git a/build/package/docker_run b/build/package/docker_run
old mode 100755
new mode 100644
diff --git a/build/package/docker_script b/build/package/docker_script
old mode 100755
new mode 100644
diff --git a/build/package/files/etc/init.d/api-umbrella b/build/package/files/etc/init.d/api-umbrella
old mode 100755
new mode 100644
diff --git a/build/package/parse_version b/build/package/parse_version
old mode 100755
new mode 100644
diff --git a/build/package/publish b/build/package/publish
old mode 100755
new mode 100644
diff --git a/build/package/scripts/after-install b/build/package/scripts/after-install
old mode 100755
new mode 100644
diff --git a/build/package/scripts/after-remove b/build/package/scripts/after-remove
old mode 100755
new mode 100644
diff --git a/build/package/scripts/before-remove b/build/package/scripts/before-remove
old mode 100755
new mode 100644
diff --git a/build/package/verify/docker_run b/build/package/verify/docker_run
old mode 100755
new mode 100644
diff --git a/build/package/verify/docker_script b/build/package/verify/docker_script
old mode 100755
new mode 100644
diff --git a/build/package/verify/download_previous_packages b/build/package/verify/download_previous_packages
old mode 100755
new mode 100644
diff --git a/build/scripts/distclean b/build/scripts/distclean
old mode 100755
new mode 100644
diff --git a/build/scripts/download_cmake b/build/scripts/download_cmake
old mode 100755
new mode 100644
diff --git a/build/scripts/install_build_dependencies b/build/scripts/install_build_dependencies
old mode 100755
new mode 100644
diff --git a/config/default.yml b/config/default.yml
index 21486ff2f..34e5fe1fb 100644
--- a/config/default.yml
+++ b/config/default.yml
@@ -58,7 +58,17 @@ gatekeeper:
- header
- getParam
- basicAuthUsername
- api_key_cache: true
+ api_key_cache: false
+ positive_ttl: 120
+ negative_ttl: 60
+ idp_providers:
+ - fiware-oauth2
+ - github-oauth2
+ - facebook-oauth2
+ - google-oauth2
+ default_idp:
+ backend_name: fiware-oauth2
+ host: http://138.4.7.8:8000
trafficserver:
host: 127.0.0.1
port: 14009
@@ -283,12 +293,12 @@ apiSettings:
message: The requested URL was not found on this server.
api_key_missing:
status_code: 403
- code: API_KEY_MISSING
- message: No api_key was supplied. Get one at {{signup_url}}
+ code: API_KEY_OR_TOKEN_MISSING
+ message: No api_key or token was supplied. Get one at {{signup_url}}
api_key_invalid:
status_code: 403
- code: API_KEY_INVALID
- message: An invalid api_key was supplied. Get one at {{signup_url}}
+ code: API_KEY_OR_TOKEN_INVALID
+ message: An invalid api_key or token was supplied. Get one at {{signup_url}}
api_key_disabled:
status_code: 403
code: API_KEY_DISABLED
@@ -299,8 +309,12 @@ apiSettings:
message: The api_key supplied has not been verified yet. Please check your e-mail to verify the API key. Contact us at {{contact_url}} for assistance
api_key_unauthorized:
status_code: 403
- code: API_KEY_UNAUTHORIZED
- message: The api_key supplied is not authorized to access the given service. Contact us at {{contact_url}} for assistance
+ code: API_KEY_OR_TOKEN_UNAUTHORIZED
+ message: The api_key or token supplied is not authorized to access the given service. Contact us at {{contact_url}} for assistance
+ not_trusted_app:
+ status_code: 403
+ code: NOT_TRUSTED_APPLICATION
+ message: The application trying to access the API_BACKEND is not trusted
over_rate_limit:
status_code: 429
code: OVER_RATE_LIMIT
diff --git a/configure b/configure
old mode 100755
new mode 100644
diff --git a/docker-ging/Dockerfile b/docker-ging/Dockerfile
new file mode 100644
index 000000000..27a0ccaf8
--- /dev/null
+++ b/docker-ging/Dockerfile
@@ -0,0 +1,23 @@
+FROM centos:centos6
+
+ENV API_UMBRELLA_VERSION 0.14.4-1~centos
+
+# Install API Umbrella
+RUN yum -y update; yum clean all
+RUN yum -y install git
+RUN groupadd -r api-umbrella && \
+useradd -r -g api-umbrella -s /sbin/nologin -d /opt/api-umbrella -c "API Umbrella user" api-umbrella
+RUN git clone https://github.com/ging/api-umbrella.git
+RUN chmod 775 -R ./api-umbrella
+RUN cd ./api-umbrella && ./build/scripts/install_build_dependencies && ./configure && make && make install
+
+
+# Define mountable directories
+VOLUME ["/etc/api-umbrella", "/opt/api-umbrella/var/db", "/opt/api-umbrella/var/log"]
+
+# Expose HTTP and HTTPS ports
+EXPOSE 80 443
+
+# Run the API Umbrella service
+CMD ["api-umbrella", "run"]
+
diff --git a/docker/dev/docker-start b/docker/dev/docker-start
old mode 100755
new mode 100644
diff --git a/docs/idp-doc.md b/docs/idp-doc.md
new file mode 100644
index 000000000..7cec0db15
--- /dev/null
+++ b/docs/idp-doc.md
@@ -0,0 +1,221 @@
+## External IdP Validation
+
+This new feature allows to the API-umbrella users
+the possibility of make request to a registered API
+ backend, using an API key or an OAuth2 token.
+ If the user uses a token in the request, this token is verified using an external IdP, once the token is validated the user information is retrieved and redirect to the API backend following the usual workflow.
+ The list of IdP's
+ included in this development are:
+
+* Fiware
+* Google
+* Facebook
+* GitHub
+
+Hence, after the inclusion of this feature,
+the gatekeeper architecture is modified
+as is showed in the next figure:
+
+
+
+## Getting Started
+
+### Installation
+For using API-Umbrella with External IdP validation, you have to clone
+this repo and install API-Umbrella from source code. The instructions fordoing this are:
+
+Note: This installation was tested with centos 6 and 7 with other Linux
+distribution should work too but, is recommended to use centos
+
+First, clone the repo and install:
+
+```
+$ git clone https://github.com/ging/api-umbrella.git
+$ chmod 775 -R ./api-umbrella
+$ cd api-umbrella
+$ sudo ./build/scripts/install_build_dependencies
+$ ./configure
+$ make
+$ sudo make install
+```
+This process could take some minutes while it download and install the dependencies.
+
+Second, start API-Umbrella
+
+```
+sudo /etc/init.d/api-umbrella start
+```
+### Docker API-Umbrella
+
+Also, you have the option of use a docker container instead of install
+API-Umbrella. The instructions for creating and running the docker
+container with this version of API umbrella are:
+
+You can run directly the container pulling the image from the docker hub:
+
+```
+$ docker run -d --name=api-umbrella -p 80:80 -p 443:443 martel/api-umbrella
+```
+
+Or build the API-Umbrella image and run the container:
+
+```
+$ git clone https://github.com/ging/api-umbrella.git
+$ cd api-umbrella/docker-ging
+$ docker build -t umbrella:0.14.4 .
+```
+
+Once you have your api-umbrella image, you can run the container and use it
+
+```
+$ docker run -d --name=api-umbrella -p 80:80 -p 443:443 umbrella:0.14.4
+```
+
+### Admin and User guide
+
+At this point, you can perform the same operations described in
+[getting started](https://api-umbrella.readthedocs.org/en/latest/getting-started.html). but Also
+in this section is included the guide of how to create API backends for processing
+the requests using Oauth2 token and external IdP's
+
+#### Registering and API-Backend uding API REST
+
+The procedure of how you can create a request using an REST call is available in the official documentation but,
+for using the external validation feature you need to include in you JSON body request the field ** require_idp: ** where IdP value could be one of this: fiware-oauth2, google-oauth2, facebook-oauth2, github-oauth2.
+
+An request example for registring a API-backend with a generic parameters is:
+
+```
+curl -k -X POST "https:///api-umbrella/v1/apis" -H "X-Api-Key: " -H "X-Admin-Auth-Token: " -H "Accept: application/json" -H "Content-Type: application/json" -d @- </?token="
+
+```
+An example of using the google maps API backend registered in API-Umbrella:
+
+```
+curl -k "https://127.0.0.1/distance1/maps/api/distancematrix/json?units=imperial&origins=Washington,DC&destinations=New+York+City,NY&token=XXXXXXXXXX"
+```
+Output:
+```
+{
+ "destination_addresses" : [ "New York, NY, USA" ],
+ "origin_addresses" : [ "Washington, DC, USA" ],
+ "rows" : [
+ {
+ "elements" : [
+ {
+ "distance" : {
+ "text" : "225 mi",
+ "value" : 361940
+ },
+ "duration" : {
+ "text" : "3 hours 51 mins",
+ "value" : 13839
+ },
+ "status" : "OK"
+ }
+ ]
+ }
+ ],
+ "status" : "OK"
+}
+
+```
+
+For sending the token via header:
+
+```
+curl -k -H "X-Auth-Token:" "https:///"
+```
+
+An example using the same API backend of google maps.
+
+```
+curl -k -H "X-Auth-Token:XXXXXX" "https://127.0.0.1/distance/maps/api/distancematrix/json?units=imperial&origins=Washington,DC&destinations=New+York+City,NY"
+```
+Output:
+```
+{
+ "destination_addresses" : [ "New York, NY, USA" ],
+ "origin_addresses" : [ "Washington, DC, USA" ],
+ "rows" : [
+ {
+ "elements" : [
+ {
+ "distance" : {
+ "text" : "225 mi",
+ "value" : 361940
+ },
+ "duration" : {
+ "text" : "3 hours 51 mins",
+ "value" : 13839
+ },
+ "status" : "OK"
+ }
+ ]
+ }
+ ],
+ "status" : "OK"
+}
+
+```
+For any additional questions or support please send an email to:
+
+*
+
diff --git a/docs/images/create-backend-ex.png b/docs/images/create-backend-ex.png
new file mode 100644
index 000000000..9e9144ec5
Binary files /dev/null and b/docs/images/create-backend-ex.png differ
diff --git a/docs/images/create-backend.png b/docs/images/create-backend.png
new file mode 100644
index 000000000..95b7bd570
Binary files /dev/null and b/docs/images/create-backend.png differ
diff --git a/docs/images/idp-arch.png b/docs/images/idp-arch.png
new file mode 100644
index 000000000..4a521dd0a
Binary files /dev/null and b/docs/images/idp-arch.png differ
diff --git a/scripts/fix-log-geoip/fix b/scripts/fix-log-geoip/fix
old mode 100755
new mode 100644
diff --git a/scripts/generate_user_agent_data b/scripts/generate_user_agent_data
old mode 100755
new mode 100644
diff --git a/scripts/import_access_logs/import b/scripts/import_access_logs/import
old mode 100755
new mode 100644
diff --git a/scripts/replay_logs b/scripts/replay_logs
old mode 100755
new mode 100644
diff --git a/src/api-umbrella/admin-ui/app/components/apis/settings/common-fields.js b/src/api-umbrella/admin-ui/app/components/apis/settings/common-fields.js
index a221eb23f..ff4e60d0f 100644
--- a/src/api-umbrella/admin-ui/app/components/apis/settings/common-fields.js
+++ b/src/api-umbrella/admin-ui/app/components/apis/settings/common-fields.js
@@ -17,14 +17,20 @@ export default Component.extend({
{ id: false, name: I18n.t('admin.api.settings.disable_api_key_options.required') },
{ id: true, name: I18n.t('admin.api.settings.disable_api_key_options.disabled') },
];
-
+ this.requireIdpOptions: [
+ { id: null, name: I18n.t('admin.api.settings.require_idp_options.inherit') },
+ { id: 'none', name: I18n.t('admin.api.settings.require_idp_options.none') },
+ { id: 'fiware-oauth2', name: "FIWARE" },
+ { id: 'github-oauth2', name: "GitHub" },
+ { id: 'facebook-oauth2', name: "Facebook" },
+ { id: 'google-oauth2', name: "Google" },
+ ];
this.apiKeyVerificationLevelOptions = [
{ id: null, name: I18n.t('admin.api.settings.api_key_verification_level_options.inherit') },
{ id: 'none', name: I18n.t('admin.api.settings.api_key_verification_level_options.none') },
{ id: 'transition_email', name: I18n.t('admin.api.settings.api_key_verification_level_options.transition_email') },
{ id: 'required_email', name: I18n.t('admin.api.settings.api_key_verification_level_options.required_email') },
];
-
this.passApiKeyOptions = [
{ id: 'header', name: I18n.t('admin.api.settings.pass_api_key_header') },
{ id: 'param', name: I18n.t('admin.api.settings.pass_api_key_param') },
diff --git a/src/api-umbrella/admin-ui/app/models/api/settings.js b/src/api-umbrella/admin-ui/app/models/api/settings.js
index 9dffe8510..9765c68f3 100644
--- a/src/api-umbrella/admin-ui/app/models/api/settings.js
+++ b/src/api-umbrella/admin-ui/app/models/api/settings.js
@@ -10,6 +10,7 @@ export default DS.Model.extend({
requireHttps: DS.attr(),
disableApiKey: DS.attr(),
apiKeyVerificationLevel: DS.attr(),
+ requireIdp: DS.attr(),
requiredRoles: DS.attr(),
requiredRolesOverride: DS.attr(),
allowedIps: DS.attr(),
diff --git a/src/api-umbrella/admin-ui/app/routes/apis/form.js b/src/api-umbrella/admin-ui/app/routes/apis/form.js
index 3573dd1d3..e85c6355a 100644
--- a/src/api-umbrella/admin-ui/app/routes/apis/form.js
+++ b/src/api-umbrella/admin-ui/app/routes/apis/form.js
@@ -6,7 +6,9 @@ import { hash } from 'rsvp';
export default Base.extend(Confirmation, UncachedModel, {
// Return a promise for loading multiple models all together.
fetchModels(record) {
- return hash({
+
+ //TODO: add external IDPs config here
+ return Ember.RSVP.hash({
record: record,
roleOptions: this.get('store').findAll('api-user-role', { reload: true }),
});
diff --git a/src/api-umbrella/admin-ui/app/templates/components/apis/settings/common-fields.hbs b/src/api-umbrella/admin-ui/app/templates/components/apis/settings/common-fields.hbs
index a03e3faec..ec5978edd 100644
--- a/src/api-umbrella/admin-ui/app/templates/components/apis/settings/common-fields.hbs
+++ b/src/api-umbrella/admin-ui/app/templates/components/apis/settings/common-fields.hbs
@@ -2,6 +2,7 @@
{{f.select-field "requireHttps" label=(t "admin.api.settings.require_https") tooltip=(t "admin.api.settings.require_https_tooltip_markdown") options=requireHttpsOptions}}
{{f.select-field "disableApiKey" label=(t "admin.api.settings.disable_api_key") options=disableApiKeyOptions}}
{{f.select-field "apiKeyVerificationLevel" label=(t "admin.api.settings.api_key_verification_level") options=apiKeyVerificationLevelOptions}}
+ {{f.select-field "requireIdp" label=(t "admin.api.settings.require_idp") options=requireIdpOptions}}
{{f.selectize-field "requiredRolesString" label=(t "admin.api.settings.required_roles") tooltip=(t "admin.api.settings.required_roles_tooltip_markdown") options=roleOptions}}
{{#if isSubSettings}}
{{f.checkbox-field "requiredRolesOverride" label=(t "admin.api.settings.required_roles_override") tooltip=(t "admin.api.settings.required_roles_override_tooltip_markdown")}}
diff --git a/src/api-umbrella/proxy/hooks/rewrite.lua b/src/api-umbrella/proxy/hooks/rewrite.lua
index c81c9e87f..2072e5386 100644
--- a/src/api-umbrella/proxy/hooks/rewrite.lua
+++ b/src/api-umbrella/proxy/hooks/rewrite.lua
@@ -17,6 +17,7 @@ wait_for_setup()
-- ngx.var lookups are apparently somewhat expensive.
ngx.ctx.args = ngx_var.args
ngx.ctx.arg_api_key = ngx_var.arg_api_key
+ngx.ctx.arg_token = ngx_var.arg_token
if(config["router"]["match_x_forwarded_host"]) then
ngx.ctx.host = ngx_var.http_x_forwarded_host or ngx_var.http_host or ngx_var.host
else
@@ -24,6 +25,7 @@ else
end
ngx.ctx.host_normalized = host_normalize(ngx.ctx.host)
ngx.ctx.http_x_api_key = ngx_var.http_x_api_key
+ngx.ctx.http_x_auth_token = ngx_var.http_x_auth_token
ngx.ctx.port = ngx_var.real_port
ngx.ctx.protocol = ngx_var.real_scheme
ngx.ctx.remote_addr = ngx_var.remote_addr
@@ -72,4 +74,4 @@ else
else
error_handler(api_err)
end
-end
+end
\ No newline at end of file
diff --git a/src/api-umbrella/proxy/middleware/api_key_validator.lua b/src/api-umbrella/proxy/middleware/api_key_validator.lua
index ab1447b32..128c93c05 100644
--- a/src/api-umbrella/proxy/middleware/api_key_validator.lua
+++ b/src/api-umbrella/proxy/middleware/api_key_validator.lua
@@ -6,32 +6,56 @@ local is_empty = types.is_empty
local function resolve_api_key()
local api_key_methods = config["gatekeeper"]["api_key_methods"]
- local api_key
+ local key = {key_value="", key_type="", idp=nil, trusted_apps=nil}
+ -- The api_key variable is a dictionary compose by three elements, the key_value which stores
+ -- the api_key value or the user token value, the key_type field in where is stored
+ -- the type of key that was provided by the user, it value could be an api_key or a token, Finally
+ -- the idp field indicates, if the api-backend have an IdP registred for the token validation
+ -- The validation process is made for all the api_key_methods (except basicAuthUsername)
+ -- declared in the configuration file, checking if the user sends an api_key or token
+ -- Only the header and get_param methods are supported by the token validation.
for _, method in ipairs(api_key_methods) do
- if method == "header" then
- api_key = ngx.ctx.http_x_api_key
- elseif method == "getParam" then
- api_key = ngx.ctx.arg_api_key
- elseif method == "basicAuthUsername" then
- api_key = ngx.ctx.remote_user
+ if method == "header" and ngx.ctx.http_x_api_key then
+ key.key_value = ngx.ctx.http_x_api_key
+ key.key_type = "api_key"
+ elseif ngx.ctx.http_x_auth_token then
+ key.key_value = ngx.ctx.http_x_auth_token
+ key.key_type = "token"
+ elseif method == "getParam" and ngx.ctx.arg_api_key then
+ key.key_value = ngx.ctx.arg_api_key
+ key.key_type = "api_key"
+ elseif ngx.ctx.arg_token then
+ key.key_value = ngx.ctx.arg_token
+ key.key_type = "token"
+ elseif method == "basicAuthUsername" and ngx.ctx.remote_user then
+ key.key_value = ngx.ctx.remote_user
+ key.key_type = "api_key"
end
- if not is_empty(api_key) then
+ if not is_empty(key["key_value"]) then
break
end
end
-- Store the api key for logging.
- ngx.ctx.api_key = api_key
+ ngx.ctx.api_key = key["key_value"]
- return api_key
+ return key
end
return function(settings)
-- Find the API key in the header, query string, or HTTP auth.
local api_key = resolve_api_key()
- if is_empty(api_key) then
+ -- Find if and IdP was set
+ if settings["require_idp"] then
+ api_key.idp=config["gatekeeper"]["default_idp"]
+ api_key.idp=settings["require_idp"]
+ api_key.trusted_apps = settings["trusted_apps"]
+ api_key.app_id = settings["idp_app_id"]
+ api_key.mode = settings["idp_mode"]
+ end
+ if is_empty(api_key["key_value"]) then
if settings and settings["disable_api_key"] then
return nil
else
@@ -44,10 +68,14 @@ return function(settings)
if not user then
return nil, "api_key_invalid"
end
+ -- Verify if the app that makes the request is in the trusted app list of the API Backend
+ if api_key["key_type"]== "token" and user["trusted_app"]== "not_trusted" then
+ return nil, "not_trusted_app"
+ end
-- Store the api key on the user object for easier access (the user object
-- doesn't contain it directly, to save memory storage in the lookup table).
- user["api_key"] = api_key
+ user["api_key"] = api_key["key_value"]
-- Store user details for logging.
ngx.ctx.user_id = user["id"]
@@ -76,4 +104,4 @@ return function(settings)
end
return user
-end
+end
\ No newline at end of file
diff --git a/src/api-umbrella/proxy/user_store.lua b/src/api-umbrella/proxy/user_store.lua
index 6ca87e4e2..5413c0102 100644
--- a/src/api-umbrella/proxy/user_store.lua
+++ b/src/api-umbrella/proxy/user_store.lua
@@ -8,19 +8,35 @@ local mongo = require "api-umbrella.utils.mongo"
local shcache = require "shcache"
local types = require "pl.types"
local utils = require "api-umbrella.proxy.utils"
+local idp = require "api-umbrella.utils.idp"
+local trusted_app = require "api-umbrella.utils.trusted_app_validation"
local cache_computed_settings = utils.cache_computed_settings
local is_empty = types.is_empty
local function lookup_user(api_key)
- local raw_user, err = mongo.first("api_users", {
- query = {
- api_key = api_key,
- },
- })
-
- if err then
- ngx.log(ngx.ERR, "failed to fetch user from mongodb: ", err)
+ local raw_user
+ local db_err
+ local idp_err
+
+ -- Checking the field of api_key ["key_type"], if the key_type is api_key
+ -- the api_key value is checked in the database and retrieve the user information
+ -- else if the key_type is token, the token is checked using the corresponding IdP
+ -- registred in the api-backend and the user information is retrieved
+
+ if not api_key["key_type"] or api_key["key_type"] == "api_key" then
+ raw_user, db_err = mongo.first("api_users", {
+ query = {
+ api_key = api_key["key_value"],
+ },
+ })
+ elseif api_key["key_type"] == "token" and api_key["idp"]then
+ raw_user, idp_err = idp.first(api_key)
+ end
+ if idp_err then
+ ngx.log(ngx.ERR, "failed to autenticate , status code:", idp_err)
+ elseif db_err then
+ ngx.log(ngx.ERR, "failed to fetch user from mongodb", db_err)
elseif raw_user then
local user = utils.pick_where_present(raw_user, {
"created_at",
@@ -32,19 +48,31 @@ local function lookup_user(api_key)
"settings",
"throttle_by_ip",
})
-
-- Ensure IDs get stored as strings, even if Mongo ObjectIds are in use.
- if raw_user["_id"] and raw_user["_id"]["$oid"] then
+ if api_key["key_type"]=="api_key" and raw_user["_id"] and raw_user["_id"]["$oid"] then
user["id"] = raw_user["_id"]["$oid"]
else
user["id"] = raw_user["_id"]
end
+ if api_key["idp"] and api_key["key_type"]=="token" and api_key["idp"]== "fiware-oauth2" then
+ user["id"] = raw_user.id
+ user["email"] = raw_user.email
+ user["trusted_app"]= trusted_app.trusted_app_validation(raw_user.app_id,api_key["trusted_apps"])
+ elseif api_key["idp"] and api_key["key_type"]=="token" and api_key["idp"]~= "fiware-oauth2" then
+ user["id"] = raw_user.name
+ user["email"] = raw_user.email
+ end
+
-- Invert the array of roles into a hashy table for more optimized
-- lookups (so we can just check if the key exists, rather than
-- looping over each value).
+ -- Moreover, in case that the user information have been retrieved using a token validation,
+ -- the roles associated with the token are stored in user ["roles"]
if user["roles"] then
user["roles"] = invert_table(user["roles"])
+ elseif api_key["idp"] and api_key["key_type"]=="token" and api_key["idp"]== "fiware-oauth2" and raw_user.Roles then
+ user["roles"] = invert_table(raw_user.Roles)
end
if user["created_at"] and user["created_at"]["$date"] then
@@ -103,14 +131,14 @@ function _M.get(api_key)
return nil
end
- user = shared_cache:load(api_key)
+ user = shared_cache:load(api_key["key_value"])
if user then
- local_cache:set(api_key, user, 2)
+ local_cache:set(api_key["key_value"], user, 2)
else
- local_cache:set(api_key, EMPTY_DATA, 2)
+ local_cache:set(api_key["key_value"], EMPTY_DATA, 2)
end
return user
end
-return _M
+return _M
\ No newline at end of file
diff --git a/src/api-umbrella/utils/idp.lua b/src/api-umbrella/utils/idp.lua
new file mode 100644
index 000000000..b992269bf
--- /dev/null
+++ b/src/api-umbrella/utils/idp.lua
@@ -0,0 +1,64 @@
+local http = require "resty.http"
+local cjson = require "cjson"
+local _M = {}
+
+-- Function to connect with an IdP service (Google, Facebook, Fiware, Github) for checking
+-- if a token is valid and retrieve the user properties. The function takes
+-- the token provided by the user and the IdP provider registered in the api-backend
+-- for checking if the token is valid making a validation request to the corresponding IdP.
+-- If the token is valid, the user information stored in the IdP is retrieved.
+
+function _M.first(dict)
+ local idp_back_name = dict["idp"]
+ local token = dict["key_value"]
+ local idp_host, result, res, err, rpath,resource, method
+ local ssl=false
+ local app_id = dict["app_id"]
+ local mode = dict["mode"]
+ local httpc = http.new()
+ httpc:set_timeout(45000)
+
+ if config["nginx"]["lua_ssl_trusted_certificate"] then
+ ssl=true
+ end
+ local rquery = "access_token="..token
+ if idp_back_name == "google-oauth2" then
+ rpath = "/oauth2/v3/userinfo"
+ idp_host="https://www.googleapis.com"
+ elseif idp_back_name == "fiware-oauth2" and mode == "authorization" then
+ rpath = "/user"
+ idp_host=dict["idp"]["host"]
+ resource = ngx.ctx.uri
+ method = ngx.ctx.request_method
+ rquery = "access_token="..token.."&app_id="..app_id.."&resource="..resource.."&action="..method
+ elseif idp_back_name == "fiware-oauth2" and mode == "authentication" then
+ rpath = "/user"
+ idp_host=dict["idp"]["host"]
+ rquery = "access_token="..token.."&app_id="..app_id
+ elseif idp_back_name == "facebook-oauth2" then
+ rpath = "/me"
+ idp_host="https://graph.facebook.com"
+ rquery = "fields=id,name,email&access_token="..token
+ elseif idp_back_name == "github-oauth2" then
+ rpath = "/user"
+ idp_host="https://api.github.com"
+ end
+
+ res, err = httpc:request_uri(idp_host..rpath,{
+ method = "GET",
+ query = rquery,
+ ssl_verify = ssl,
+ })
+
+ if res and res.status == 200 then
+ local body= res.body
+ if not body then
+ return nil
+ end
+ result = cjson.decode(body)
+ end
+
+ return result, err
+end
+
+return _M
\ No newline at end of file
diff --git a/src/api-umbrella/utils/invert_table.lua b/src/api-umbrella/utils/invert_table.lua
index 5d0000f22..4b5a1b8f9 100644
--- a/src/api-umbrella/utils/invert_table.lua
+++ b/src/api-umbrella/utils/invert_table.lua
@@ -1,8 +1,18 @@
return function(table)
+ local numItems = 0
local inverted = {}
for key, value in pairs(table) do
- inverted[value] = key
+ if type(value)=="string" then
+ inverted[value] = key
+ else
+ for k,v in pairs(value) do
+ numItems = numItems + 1
+ end
+ if numItems > 1 then
+ value = value["name"]
+ end
+ inverted[value] = key
+ end
end
-
return inverted
end
diff --git a/src/api-umbrella/utils/trusted_app_validation.lua b/src/api-umbrella/utils/trusted_app_validation.lua
new file mode 100644
index 000000000..1b3058dcd
--- /dev/null
+++ b/src/api-umbrella/utils/trusted_app_validation.lua
@@ -0,0 +1,17 @@
+--
+-- Created by: anmunoz
+-- Date: 3/16/18
+-- Time: 2:03 PM
+--
+local _output_value = {}
+function _output_value.trusted_app_validation(app_id_scope,trusted_app_list)
+ for _, trusted_app_id in ipairs(trusted_app_list) do
+ if app_id_scope == trusted_app_id.id then
+ _output_value="trusted"
+ return _output_value
+ end
+ end
+ _output_value="not_trusted"
+ return _output_value
+end
+return _output_value
\ No newline at end of file
diff --git a/src/api-umbrella/web-app/app/controllers/api/v1/apis_controller.rb b/src/api-umbrella/web-app/app/controllers/api/v1/apis_controller.rb
index 38550bc96..462a7c50e 100644
--- a/src/api-umbrella/web-app/app/controllers/api/v1/apis_controller.rb
+++ b/src/api-umbrella/web-app/app/controllers/api/v1/apis_controller.rb
@@ -94,6 +94,7 @@ def api_params
:disable_api_key,
:api_key_verification_level,
:api_key_verification_transition_start_at,
+ :require_idp,
:rate_limit_mode,
:anonymous_rate_limit_behavior,
:authenticated_rate_limit_behavior,
diff --git a/src/api-umbrella/web-app/app/models/api/settings.rb b/src/api-umbrella/web-app/app/models/api/settings.rb
index 3d8e11aa0..3fcda9bad 100644
--- a/src/api-umbrella/web-app/app/models/api/settings.rb
+++ b/src/api-umbrella/web-app/app/models/api/settings.rb
@@ -10,6 +10,7 @@ class Api::Settings
field :disable_api_key, :type => Boolean
field :api_key_verification_level, :type => String
field :api_key_verification_transition_start_at, :type => Time
+ field :require_idp, :type => String
field :required_roles, :type => Array
field :required_roles_override, :type => Boolean
field :allowed_ips, :type => Array
diff --git a/src/api-umbrella/web-app/bin/bundle b/src/api-umbrella/web-app/bin/bundle
old mode 100755
new mode 100644
diff --git a/src/api-umbrella/web-app/bin/delayed_job b/src/api-umbrella/web-app/bin/delayed_job
old mode 100755
new mode 100644
diff --git a/src/api-umbrella/web-app/bin/rails b/src/api-umbrella/web-app/bin/rails
old mode 100755
new mode 100644
diff --git a/src/api-umbrella/web-app/bin/rake b/src/api-umbrella/web-app/bin/rake
old mode 100755
new mode 100644
diff --git a/src/api-umbrella/web-app/bin/setup b/src/api-umbrella/web-app/bin/setup
old mode 100755
new mode 100644
diff --git a/src/api-umbrella/web-app/bin/spring b/src/api-umbrella/web-app/bin/spring
old mode 100755
new mode 100644
diff --git a/src/api-umbrella/web-app/config/locales/en.yml b/src/api-umbrella/web-app/config/locales/en.yml
index 6186b1afa..12bb353a4 100644
--- a/src/api-umbrella/web-app/config/locales/en.yml
+++ b/src/api-umbrella/web-app/config/locales/en.yml
@@ -139,6 +139,10 @@ en:
none: None - API keys can be used without any verification
transition_email: E-mail verification transition - Existing API keys will continue to work, new API keys will only work if verified
required_email: E-mail verification required - Existing API keys will break, only new API keys will work if verified
+ require_idp: External Identity Provider
+ require_idp_options:
+ inherit: Inherit (default - none)
+ none: None
required_roles: Required Roles
required_roles_tooltip_markdown: |-
Define roles that API keys must have in order to access this API. If multiple roles are set, then the API key must have all of the roles.
diff --git a/src/api-umbrella/web-app/script/migrate_logs b/src/api-umbrella/web-app/script/migrate_logs
old mode 100755
new mode 100644
diff --git a/src/api-umbrella/web-app/script/migrate_users b/src/api-umbrella/web-app/script/migrate_users
old mode 100755
new mode 100644
diff --git a/templates/etc/perp/.boot/rc.log b/templates/etc/perp/.boot/rc.log
old mode 100755
new mode 100644
diff --git a/templates/etc/perp/.boot/rc.perp.mustache b/templates/etc/perp/.boot/rc.perp.mustache
old mode 100755
new mode 100644
diff --git a/templates/etc/perp/dev-env-ember-server/rc.log b/templates/etc/perp/dev-env-ember-server/rc.log
old mode 100755
new mode 100644
diff --git a/templates/etc/perp/dev-env-ember-server/rc.main.mustache b/templates/etc/perp/dev-env-ember-server/rc.main.mustache
old mode 100755
new mode 100644
diff --git a/templates/etc/perp/elasticsearch/rc.log b/templates/etc/perp/elasticsearch/rc.log
old mode 100755
new mode 100644
diff --git a/templates/etc/perp/elasticsearch/rc.main.mustache b/templates/etc/perp/elasticsearch/rc.main.mustache
old mode 100755
new mode 100644
diff --git a/templates/etc/perp/flume/rc.log b/templates/etc/perp/flume/rc.log
old mode 100755
new mode 100644
diff --git a/templates/etc/perp/flume/rc.main.mustache b/templates/etc/perp/flume/rc.main.mustache
old mode 100755
new mode 100644
diff --git a/templates/etc/perp/geoip-auto-updater/rc.log b/templates/etc/perp/geoip-auto-updater/rc.log
old mode 100755
new mode 100644
diff --git a/templates/etc/perp/geoip-auto-updater/rc.main.mustache b/templates/etc/perp/geoip-auto-updater/rc.main.mustache
old mode 100755
new mode 100644
diff --git a/templates/etc/perp/kylin/rc.log b/templates/etc/perp/kylin/rc.log
old mode 100755
new mode 100644
diff --git a/templates/etc/perp/kylin/rc.main.mustache b/templates/etc/perp/kylin/rc.main.mustache
old mode 100755
new mode 100644
diff --git a/templates/etc/perp/kylin/rc.run.mustache b/templates/etc/perp/kylin/rc.run.mustache
old mode 100755
new mode 100644
diff --git a/templates/etc/perp/mongod/rc.log b/templates/etc/perp/mongod/rc.log
old mode 100755
new mode 100644
diff --git a/templates/etc/perp/mongod/rc.main.mustache b/templates/etc/perp/mongod/rc.main.mustache
old mode 100755
new mode 100644
diff --git a/templates/etc/perp/mora/rc.log b/templates/etc/perp/mora/rc.log
old mode 100755
new mode 100644
diff --git a/templates/etc/perp/mora/rc.main.mustache b/templates/etc/perp/mora/rc.main.mustache
old mode 100755
new mode 100644
diff --git a/templates/etc/perp/nginx-reloader/rc.log b/templates/etc/perp/nginx-reloader/rc.log
old mode 100755
new mode 100644
diff --git a/templates/etc/perp/nginx-reloader/rc.main.mustache b/templates/etc/perp/nginx-reloader/rc.main.mustache
old mode 100755
new mode 100644
diff --git a/templates/etc/perp/nginx/rc.log b/templates/etc/perp/nginx/rc.log
old mode 100755
new mode 100644
diff --git a/templates/etc/perp/nginx/rc.main.mustache b/templates/etc/perp/nginx/rc.main.mustache
old mode 100755
new mode 100644
diff --git a/templates/etc/perp/presto/rc.log b/templates/etc/perp/presto/rc.log
old mode 100755
new mode 100644
diff --git a/templates/etc/perp/presto/rc.main.mustache b/templates/etc/perp/presto/rc.main.mustache
old mode 100755
new mode 100644
diff --git a/templates/etc/perp/rc.log.mustache b/templates/etc/perp/rc.log.mustache
old mode 100755
new mode 100644
diff --git a/templates/etc/perp/rsyslog/rc.log b/templates/etc/perp/rsyslog/rc.log
old mode 100755
new mode 100644
diff --git a/templates/etc/perp/rsyslog/rc.main.mustache b/templates/etc/perp/rsyslog/rc.main.mustache
old mode 100755
new mode 100644
diff --git a/templates/etc/perp/test-env-mailhog/rc.log b/templates/etc/perp/test-env-mailhog/rc.log
old mode 100755
new mode 100644
diff --git a/templates/etc/perp/test-env-mailhog/rc.main.mustache b/templates/etc/perp/test-env-mailhog/rc.main.mustache
old mode 100755
new mode 100644
diff --git a/templates/etc/perp/test-env-mongo-orchestration/rc.log b/templates/etc/perp/test-env-mongo-orchestration/rc.log
old mode 100755
new mode 100644
diff --git a/templates/etc/perp/test-env-mongo-orchestration/rc.main.mustache b/templates/etc/perp/test-env-mongo-orchestration/rc.main.mustache
old mode 100755
new mode 100644
diff --git a/templates/etc/perp/test-env-nginx/rc.log b/templates/etc/perp/test-env-nginx/rc.log
old mode 100755
new mode 100644
diff --git a/templates/etc/perp/test-env-nginx/rc.main.mustache b/templates/etc/perp/test-env-nginx/rc.main.mustache
old mode 100755
new mode 100644
diff --git a/templates/etc/perp/test-env-openldap/rc.log b/templates/etc/perp/test-env-openldap/rc.log
old mode 100755
new mode 100644
diff --git a/templates/etc/perp/test-env-openldap/rc.main.mustache b/templates/etc/perp/test-env-openldap/rc.main.mustache
old mode 100755
new mode 100644
diff --git a/templates/etc/perp/test-env-unbound/rc.log b/templates/etc/perp/test-env-unbound/rc.log
old mode 100755
new mode 100644
diff --git a/templates/etc/perp/test-env-unbound/rc.main.mustache b/templates/etc/perp/test-env-unbound/rc.main.mustache
old mode 100755
new mode 100644
diff --git a/templates/etc/perp/trafficserver/rc.log b/templates/etc/perp/trafficserver/rc.log
old mode 100755
new mode 100644
diff --git a/templates/etc/perp/trafficserver/rc.main.mustache b/templates/etc/perp/trafficserver/rc.main.mustache
old mode 100755
new mode 100644
diff --git a/templates/etc/perp/web-delayed-job/rc.log b/templates/etc/perp/web-delayed-job/rc.log
old mode 100755
new mode 100644
diff --git a/templates/etc/perp/web-delayed-job/rc.main.mustache b/templates/etc/perp/web-delayed-job/rc.main.mustache
old mode 100755
new mode 100644
diff --git a/templates/etc/perp/web-puma/rc.log b/templates/etc/perp/web-puma/rc.log
old mode 100755
new mode 100644
diff --git a/templates/etc/perp/web-puma/rc.main.mustache b/templates/etc/perp/web-puma/rc.main.mustache
old mode 100755
new mode 100644
diff --git a/test/scripts/circle-ci b/test/scripts/circle-ci
old mode 100755
new mode 100644