mirror of https://gitee.com/bigwinds/arangodb
Added a REST API for user management The REST API exposes the functionality available in module "users" for HTTP access. The following methods are available: * GET /_api/user/username: fetch user information * POST /_api/user: create new user * PUT /_api/user: replace an existing user * PATCH /_api/user: (partially) update an existing user * DELETE /_api/user: remove an existing user Additionally, a module "crypto" is introduced and exposed for Javascript actions. The crypto module provides the following functions: * require("org/arangodb/crypto").md5(); * require("org/arangodb/crypto").sha256(); * require("org/arangodb/crypto").rand();
This commit is contained in:
parent
a67164b3b5
commit
3fdebb38ee
|
@ -1,6 +1,13 @@
|
|||
v1.2.beta3 (XXXX-XX-XX)
|
||||
-----------------------
|
||||
|
||||
* issue #393: added REST API for user management at /_api/user
|
||||
|
||||
* issue #393, #128: added simple cryptographic functions for user actions in module "crypto":
|
||||
* require("org/arangodb/crypto").md5()
|
||||
* require("org/arangodb/crypto").sha256()
|
||||
* require("org/arangodb/crypto").rand()
|
||||
|
||||
* added replaceByExample() Javascript and REST API method
|
||||
|
||||
* added updateByExample() Javascript and REST API method
|
||||
|
|
|
@ -13,8 +13,8 @@ will allow the administrator to restrict access to collections and queries to
|
|||
certain users, given them either read or write access.
|
||||
|
||||
Currently, you can only secure the access to ArangoDB in an all-or-nothing
|
||||
fashion. The collection `_users` contains all user and the SHA256 of their
|
||||
passwords. A user can be active or inactive. A typical document of this
|
||||
fashion. The collection `_users` contains all users and a salted SHA256 hash
|
||||
of their passwords. A user can be active or inactive. A typical document of this
|
||||
collection is
|
||||
|
||||
{
|
||||
|
@ -23,7 +23,7 @@ collection is
|
|||
"_key" : "1675886"
|
||||
"active" : true,
|
||||
"user" : "admin",
|
||||
"password" : "8c6976e5b5410415bde908bd4dee15dfb167a9c873fc4bb8a81f6f2ab448a918"
|
||||
"password" : "$1$96b646a9$c2162af67f82e1dc95877b9475ebc55f7abdacad58c2b57848b2bc84acf8ebb6"
|
||||
}
|
||||
|
||||
Command-Line Options for the Authentication and Authorisation {#DbaManualAuthenticationCommandLine}
|
||||
|
@ -45,10 +45,18 @@ web interface.
|
|||
@anchor UserManagementSave
|
||||
@copydetails JSF_saveUser
|
||||
|
||||
@CLEARPAGE
|
||||
@anchor UserManagementDocument
|
||||
@copydetails JSF_documentUser
|
||||
|
||||
@CLEARPAGE
|
||||
@anchor UserManagementReplace
|
||||
@copydetails JSF_replaceUser
|
||||
|
||||
@CLEARPAGE
|
||||
@anchor UserManagementUpdate
|
||||
@copydetails JSF_updateUser
|
||||
|
||||
@CLEARPAGE
|
||||
@anchor UserManagementRemove
|
||||
@copydetails JSF_removeUser
|
||||
|
|
|
@ -3,5 +3,7 @@ TOC {#UserManagementTOC}
|
|||
|
||||
- @ref UserManagementIntro
|
||||
- @ref UserManagementSave "users.save"
|
||||
- @ref UserManagementDocument "users.document"
|
||||
- @ref UserManagementReplace "users.replace"
|
||||
- @ref UserManagementUpdate "users.update"
|
||||
- @ref UserManagementRemove "users.remove"
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
HTTP Interface for User Management {#HttpUser}
|
||||
==============================================
|
||||
|
||||
@NAVIGATE_HttpUser
|
||||
@EMBEDTOC{HttpUserTOC}
|
||||
|
||||
User Management {#HttpUserIntro}
|
||||
================================
|
||||
|
||||
This is an introduction to ArangoDB's Http interface for managing users.
|
||||
|
||||
The interface provides a simple means to add, update, and remove users.
|
||||
|
||||
@anchor HttpUserSave
|
||||
@copydetails JSF_POST_api_user
|
||||
|
||||
@CLEARPAGE
|
||||
@anchor HttpUserReplace
|
||||
@copydetails JSF_PUT_api_user
|
||||
|
||||
@CLEARPAGE
|
||||
@anchor HttpUserUpdate
|
||||
@copydetails JSF_PATCH_api_user
|
||||
|
||||
@CLEARPAGE
|
||||
@anchor HttpUserRemove
|
||||
@copydetails JSF_DELETE_api_user
|
||||
|
||||
@CLEARPAGE
|
||||
@anchor HttpUserDocument
|
||||
@copydetails JSF_GET_api_user
|
|
@ -0,0 +1,10 @@
|
|||
TOC {#HttpUserTOC}
|
||||
===================
|
||||
|
||||
- @ref HttpUser
|
||||
- @ref HttpUserIntro
|
||||
- @ref HttpUserSave "POST /_api/user"
|
||||
- @ref HttpUserReplace "PUT /_api/user/username"
|
||||
- @ref HttpUserUpdate "PATCH /_api/user/username"
|
||||
- @ref HttpUserRemove "DELETE /_api/user/username"
|
||||
- @ref HttpUserDocument "GET /_api/user/username"
|
|
@ -19,6 +19,7 @@ ArangoDB for API Implementors (@VERSION) {#ImplementorManual}
|
|||
@CHAPTER_REF{HttpImport}
|
||||
@CHAPTER_REF{HttpBatch}
|
||||
@CHAPTER_REF{HttpSystem}
|
||||
@CHAPTER_REF{HttpUser}
|
||||
@CHAPTER_REF{HttpMisc}
|
||||
@CHAPTER_REF{Communication}
|
||||
@CHAPTER_REF{NamingConventions}
|
||||
|
|
|
@ -49,6 +49,7 @@ DOXYGEN = \
|
|||
Doxygen/js/actions/system/api-query.c \
|
||||
Doxygen/js/actions/system/api-simple.c \
|
||||
Doxygen/js/actions/system/api-system.c \
|
||||
Doxygen/js/actions/system/api-user.c \
|
||||
Doxygen/js/common/bootstrap/module-console.c \
|
||||
Doxygen/js/common/bootstrap/module-fs.c \
|
||||
Doxygen/js/common/bootstrap/modules.c \
|
||||
|
@ -98,6 +99,7 @@ WIKI = \
|
|||
HttpQuery \
|
||||
HttpSimple \
|
||||
HttpSystem \
|
||||
HttpUser \
|
||||
ImpManual \
|
||||
ImpManualBasics \
|
||||
ImplementorManual \
|
||||
|
@ -131,7 +133,6 @@ WIKI = \
|
|||
SimpleQueries \
|
||||
Upgrading11 \
|
||||
Upgrading12 \
|
||||
UserManagement \
|
||||
UserManual \
|
||||
UserManualActions \
|
||||
UserManualArangosh \
|
||||
|
|
|
@ -0,0 +1,420 @@
|
|||
# coding: utf-8
|
||||
|
||||
require 'rspec'
|
||||
require './arangodb.rb'
|
||||
|
||||
describe ArangoDB do
|
||||
api = "/_api/user"
|
||||
prefix = "api-users"
|
||||
|
||||
context "user management:" do
|
||||
|
||||
before do
|
||||
(0...10).each{|i|
|
||||
ArangoDB.delete("/_api/user/users-" + i.to_s);
|
||||
}
|
||||
end
|
||||
|
||||
after do
|
||||
(0...10).each{|i|
|
||||
ArangoDB.delete("/_api/user/users-" + i.to_s);
|
||||
}
|
||||
end
|
||||
|
||||
################################################################################
|
||||
## adding users
|
||||
################################################################################
|
||||
|
||||
context "adding users" do
|
||||
|
||||
it "add user, no username" do
|
||||
body = "{ \"passwd\" : \"fox\" }"
|
||||
doc = ArangoDB.log_post("#{prefix}-add", api, :body => body)
|
||||
|
||||
doc.code.should eq(400)
|
||||
doc.headers['content-type'].should eq("application/json; charset=utf-8")
|
||||
doc.parsed_response['error'].should eq(true)
|
||||
doc.parsed_response['code'].should eq(400)
|
||||
doc.parsed_response['errorNum'].should eq(1700)
|
||||
end
|
||||
|
||||
it "add user, empty username" do
|
||||
body = "{ \"username\" : \"\", \"passwd\" : \"fox\" }"
|
||||
doc = ArangoDB.log_post("#{prefix}-add", api, :body => body)
|
||||
|
||||
doc.code.should eq(400)
|
||||
doc.headers['content-type'].should eq("application/json; charset=utf-8")
|
||||
doc.parsed_response['error'].should eq(true)
|
||||
doc.parsed_response['code'].should eq(400)
|
||||
doc.parsed_response['errorNum'].should eq(1700)
|
||||
end
|
||||
|
||||
it "add user, no passwd" do
|
||||
body = "{ \"username\" : \"users-1\" }"
|
||||
doc = ArangoDB.log_post("#{prefix}-add", api, :body => body)
|
||||
|
||||
doc.code.should eq(201)
|
||||
doc.headers['content-type'].should eq("application/json; charset=utf-8")
|
||||
doc.parsed_response['error'].should eq(false)
|
||||
doc.parsed_response['code'].should eq(201)
|
||||
|
||||
doc = ArangoDB.get(api + "/users-1")
|
||||
doc.code.should eq(200)
|
||||
doc.parsed_response['error'].should eq(false)
|
||||
doc.parsed_response['code'].should eq(200)
|
||||
doc.parsed_response['user'].should eq("users-1")
|
||||
doc.parsed_response['active'].should eq(true)
|
||||
end
|
||||
|
||||
it "add user, username and passwd" do
|
||||
body = "{ \"username\" : \"users-1\", \"passwd\" : \"fox\" }"
|
||||
doc = ArangoDB.log_post("#{prefix}-add", api, :body => body)
|
||||
|
||||
doc.code.should eq(201)
|
||||
doc.headers['content-type'].should eq("application/json; charset=utf-8")
|
||||
doc.parsed_response['error'].should eq(false)
|
||||
doc.parsed_response['code'].should eq(201)
|
||||
|
||||
doc = ArangoDB.get(api + "/users-1")
|
||||
doc.code.should eq(200)
|
||||
doc.parsed_response['error'].should eq(false)
|
||||
doc.parsed_response['code'].should eq(200)
|
||||
doc.parsed_response['user'].should eq("users-1")
|
||||
doc.parsed_response['active'].should eq(true)
|
||||
end
|
||||
|
||||
it "add user, username passwd, active, extra" do
|
||||
body = "{ \"username\" : \"users-2\", \"passwd\" : \"fox\", \"active\" : false, \"extra\" : { \"foo\" : true } }"
|
||||
doc = ArangoDB.log_post("#{prefix}-add", api, :body => body)
|
||||
|
||||
doc.code.should eq(201)
|
||||
doc.headers['content-type'].should eq("application/json; charset=utf-8")
|
||||
doc.parsed_response['error'].should eq(false)
|
||||
doc.parsed_response['code'].should eq(201)
|
||||
|
||||
doc = ArangoDB.get(api + "/users-2")
|
||||
doc.code.should eq(200)
|
||||
doc.parsed_response['error'].should eq(false)
|
||||
doc.parsed_response['code'].should eq(200)
|
||||
doc.parsed_response['user'].should eq("users-2")
|
||||
doc.parsed_response['active'].should eq(false)
|
||||
doc.parsed_response['extra'].should eq({ "foo" => true })
|
||||
end
|
||||
|
||||
it "add user, duplicate username" do
|
||||
body = "{ \"username\" : \"users-1\", \"passwd\" : \"fox\" }"
|
||||
doc = ArangoDB.log_post("#{prefix}-add", api, :body => body)
|
||||
|
||||
doc.code.should eq(201)
|
||||
doc.headers['content-type'].should eq("application/json; charset=utf-8")
|
||||
doc.parsed_response['error'].should eq(false)
|
||||
doc.parsed_response['code'].should eq(201)
|
||||
|
||||
doc = ArangoDB.log_post("#{prefix}-add", api, :body => body)
|
||||
|
||||
doc.code.should eq(400)
|
||||
doc.headers['content-type'].should eq("application/json; charset=utf-8")
|
||||
doc.parsed_response['error'].should eq(true)
|
||||
doc.parsed_response['code'].should eq(400)
|
||||
doc.parsed_response['errorNum'].should eq(1702)
|
||||
end
|
||||
end
|
||||
|
||||
################################################################################
|
||||
## replacing users
|
||||
################################################################################
|
||||
|
||||
context "replacing users" do
|
||||
it "replace, no user" do
|
||||
doc = ArangoDB.log_put("#{prefix}-replace", api)
|
||||
doc.headers['content-type'].should eq("application/json; charset=utf-8")
|
||||
doc.parsed_response['error'].should eq(true)
|
||||
doc.parsed_response['code'].should eq(400)
|
||||
end
|
||||
|
||||
it "replace non-existing user" do
|
||||
doc = ArangoDB.log_put("#{prefix}-replace", api + "/users-1")
|
||||
doc.headers['content-type'].should eq("application/json; charset=utf-8")
|
||||
doc.parsed_response['error'].should eq(true)
|
||||
doc.parsed_response['code'].should eq(404)
|
||||
end
|
||||
|
||||
it "replace already removed user" do
|
||||
body = "{ \"username\" : \"users-1\", \"passwd\" : \"fox\", \"active\" : true, \"extra\" : { \"foo\" : true } }"
|
||||
doc = ArangoDB.log_post("#{prefix}-replace", api, :body => body)
|
||||
|
||||
doc.code.should eq(201)
|
||||
|
||||
# remove
|
||||
doc = ArangoDB.log_delete("#{prefix}-replace", api + "/users-1")
|
||||
doc.headers['content-type'].should eq("application/json; charset=utf-8")
|
||||
doc.parsed_response['error'].should eq(false)
|
||||
doc.parsed_response['code'].should eq(202)
|
||||
|
||||
# now replace
|
||||
doc = ArangoDB.log_put("#{prefix}-replace", api + "/users-1")
|
||||
doc.headers['content-type'].should eq("application/json; charset=utf-8")
|
||||
doc.parsed_response['error'].should eq(true)
|
||||
doc.parsed_response['code'].should eq(404)
|
||||
end
|
||||
|
||||
it "replace, empty body" do
|
||||
body = "{ \"username\" : \"users-1\", \"passwd\" : \"fox\", \"active\" : true, \"extra\" : { \"foo\" : true } }"
|
||||
doc = ArangoDB.log_post("#{prefix}-replace", api, :body => body)
|
||||
|
||||
# replace
|
||||
body = "{ }"
|
||||
doc = ArangoDB.log_put("#{prefix}-replace", api + "/users-1", :body => body)
|
||||
doc.headers['content-type'].should eq("application/json; charset=utf-8")
|
||||
doc.parsed_response['error'].should eq(false)
|
||||
doc.parsed_response['code'].should eq(200)
|
||||
|
||||
doc = ArangoDB.get(api + "/users-1")
|
||||
doc.code.should eq(200)
|
||||
doc.parsed_response['error'].should eq(false)
|
||||
doc.parsed_response['code'].should eq(200)
|
||||
doc.parsed_response['user'].should eq("users-1")
|
||||
doc.parsed_response['active'].should eq(true)
|
||||
end
|
||||
|
||||
it "replace existing user, no passwd" do
|
||||
body = "{ \"username\" : \"users-1\", \"passwd\" : \"fox\", \"active\" : true, \"extra\" : { \"foo\" : true } }"
|
||||
doc = ArangoDB.log_post("#{prefix}-replace", api, :body => body)
|
||||
|
||||
# replace
|
||||
body = "{ \"active\" : false, \"extra\" : { \"foo\" : false } }"
|
||||
doc = ArangoDB.log_put("#{prefix}-replace", api + "/users-1", :body => body)
|
||||
doc.headers['content-type'].should eq("application/json; charset=utf-8")
|
||||
doc.parsed_response['error'].should eq(false)
|
||||
doc.parsed_response['code'].should eq(200)
|
||||
|
||||
doc = ArangoDB.get(api + "/users-1")
|
||||
doc.code.should eq(200)
|
||||
doc.parsed_response['error'].should eq(false)
|
||||
doc.parsed_response['code'].should eq(200)
|
||||
doc.parsed_response['user'].should eq("users-1")
|
||||
doc.parsed_response['active'].should eq(false)
|
||||
doc.parsed_response['extra'].should eq({ "foo" => false })
|
||||
end
|
||||
|
||||
it "replace existing user" do
|
||||
body = "{ \"username\" : \"users-1\", \"passwd\" : \"fox\", \"active\" : true, \"extra\" : { \"foo\" : true } }"
|
||||
doc = ArangoDB.log_post("#{prefix}-replace", api, :body => body)
|
||||
|
||||
# replace
|
||||
body = "{ \"passwd\" : \"fox2\", \"active\" : false, \"extra\" : { \"foo\" : false } }"
|
||||
doc = ArangoDB.log_put("#{prefix}-replace", api + "/users-1", :body => body)
|
||||
doc.headers['content-type'].should eq("application/json; charset=utf-8")
|
||||
doc.parsed_response['error'].should eq(false)
|
||||
doc.parsed_response['code'].should eq(200)
|
||||
|
||||
doc = ArangoDB.get(api + "/users-1")
|
||||
doc.code.should eq(200)
|
||||
doc.parsed_response['error'].should eq(false)
|
||||
doc.parsed_response['code'].should eq(200)
|
||||
doc.parsed_response['user'].should eq("users-1")
|
||||
doc.parsed_response['active'].should eq(false)
|
||||
doc.parsed_response['extra'].should eq({ "foo" => false })
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
################################################################################
|
||||
## updating users
|
||||
################################################################################
|
||||
|
||||
context "updating users" do
|
||||
it "update, no user" do
|
||||
doc = ArangoDB.log_patch("#{prefix}-update", api)
|
||||
doc.headers['content-type'].should eq("application/json; charset=utf-8")
|
||||
doc.parsed_response['error'].should eq(true)
|
||||
doc.parsed_response['code'].should eq(400)
|
||||
end
|
||||
|
||||
it "update non-existing user" do
|
||||
doc = ArangoDB.log_patch("#{prefix}-update", api + "/users-1")
|
||||
doc.headers['content-type'].should eq("application/json; charset=utf-8")
|
||||
doc.parsed_response['error'].should eq(true)
|
||||
doc.parsed_response['code'].should eq(404)
|
||||
end
|
||||
|
||||
it "update already removed user" do
|
||||
body = "{ \"username\" : \"users-1\", \"passwd\" : \"fox\", \"active\" : true, \"extra\" : { \"foo\" : true } }"
|
||||
doc = ArangoDB.log_post("#{prefix}-update", api, :body => body)
|
||||
|
||||
doc.code.should eq(201)
|
||||
|
||||
# remove
|
||||
doc = ArangoDB.log_delete("#{prefix}-update", api + "/users-1")
|
||||
doc.headers['content-type'].should eq("application/json; charset=utf-8")
|
||||
doc.parsed_response['error'].should eq(false)
|
||||
doc.parsed_response['code'].should eq(202)
|
||||
|
||||
# now update
|
||||
doc = ArangoDB.log_patch("#{prefix}-update", api + "/users-1")
|
||||
doc.headers['content-type'].should eq("application/json; charset=utf-8")
|
||||
doc.parsed_response['error'].should eq(true)
|
||||
doc.parsed_response['code'].should eq(404)
|
||||
end
|
||||
|
||||
it "update, empty body" do
|
||||
body = "{ \"username\" : \"users-1\", \"passwd\" : \"fox\", \"active\" : true, \"extra\" : { \"foo\" : true } }"
|
||||
doc = ArangoDB.log_post("#{prefix}-update", api, :body => body)
|
||||
|
||||
# update
|
||||
body = "{ }"
|
||||
doc = ArangoDB.log_patch("#{prefix}-update", api + "/users-1", :body => body)
|
||||
doc.headers['content-type'].should eq("application/json; charset=utf-8")
|
||||
doc.parsed_response['error'].should eq(false)
|
||||
doc.parsed_response['code'].should eq(200)
|
||||
|
||||
doc = ArangoDB.get(api + "/users-1")
|
||||
doc.code.should eq(200)
|
||||
doc.parsed_response['error'].should eq(false)
|
||||
doc.parsed_response['code'].should eq(200)
|
||||
doc.parsed_response['user'].should eq("users-1")
|
||||
doc.parsed_response['active'].should eq(true)
|
||||
doc.parsed_response['extra'].should eq({ "foo" => true })
|
||||
end
|
||||
|
||||
it "update existing user, no passwd" do
|
||||
body = "{ \"username\" : \"users-1\", \"passwd\" : \"fox\", \"active\" : true, \"extra\" : { \"foo\" : true } }"
|
||||
doc = ArangoDB.log_post("#{prefix}-update", api, :body => body)
|
||||
|
||||
# update
|
||||
body = "{ \"active\" : false, \"extra\" : { \"foo\" : false } }"
|
||||
doc = ArangoDB.log_patch("#{prefix}-update", api + "/users-1", :body => body)
|
||||
doc.headers['content-type'].should eq("application/json; charset=utf-8")
|
||||
doc.parsed_response['error'].should eq(false)
|
||||
doc.parsed_response['code'].should eq(200)
|
||||
|
||||
doc = ArangoDB.get(api + "/users-1")
|
||||
doc.code.should eq(200)
|
||||
doc.parsed_response['error'].should eq(false)
|
||||
doc.parsed_response['code'].should eq(200)
|
||||
doc.parsed_response['user'].should eq("users-1")
|
||||
doc.parsed_response['active'].should eq(false)
|
||||
doc.parsed_response['extra'].should eq({ "foo" => false })
|
||||
end
|
||||
|
||||
it "update existing user" do
|
||||
body = "{ \"username\" : \"users-1\", \"passwd\" : \"fox\", \"active\" : true, \"extra\" : { \"foo\" : true } }"
|
||||
doc = ArangoDB.log_post("#{prefix}-update", api, :body => body)
|
||||
|
||||
# update
|
||||
body = "{ \"passwd\" : \"fox2\", \"active\" : false }"
|
||||
doc = ArangoDB.log_patch("#{prefix}-update", api + "/users-1", :body => body)
|
||||
doc.headers['content-type'].should eq("application/json; charset=utf-8")
|
||||
doc.parsed_response['error'].should eq(false)
|
||||
doc.parsed_response['code'].should eq(200)
|
||||
|
||||
doc = ArangoDB.get(api + "/users-1")
|
||||
doc.code.should eq(200)
|
||||
doc.parsed_response['error'].should eq(false)
|
||||
doc.parsed_response['code'].should eq(200)
|
||||
doc.parsed_response['user'].should eq("users-1")
|
||||
doc.parsed_response['active'].should eq(false)
|
||||
doc.parsed_response['extra'].should eq({ "foo" => true })
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
################################################################################
|
||||
## removing users
|
||||
################################################################################
|
||||
|
||||
context "removing users" do
|
||||
it "remove, no user" do
|
||||
doc = ArangoDB.log_delete("#{prefix}-remove", api)
|
||||
doc.headers['content-type'].should eq("application/json; charset=utf-8")
|
||||
doc.parsed_response['error'].should eq(true)
|
||||
doc.parsed_response['code'].should eq(400)
|
||||
end
|
||||
|
||||
it "remove non-existing user" do
|
||||
doc = ArangoDB.log_delete("#{prefix}-remove", api + "/users-1")
|
||||
doc.headers['content-type'].should eq("application/json; charset=utf-8")
|
||||
doc.parsed_response['error'].should eq(true)
|
||||
doc.parsed_response['code'].should eq(404)
|
||||
end
|
||||
|
||||
it "remove already removed user" do
|
||||
body = "{ \"username\" : \"users-1\", \"passwd\" : \"fox\", \"active\" : true, \"extra\" : { \"foo\" : true } }"
|
||||
doc = ArangoDB.log_post("#{prefix}-delete", api, :body => body)
|
||||
|
||||
doc.code.should eq(201)
|
||||
|
||||
# remove for the first time
|
||||
doc = ArangoDB.log_delete("#{prefix}-remove", api + "/users-1")
|
||||
doc.headers['content-type'].should eq("application/json; charset=utf-8")
|
||||
doc.parsed_response['error'].should eq(false)
|
||||
doc.parsed_response['code'].should eq(202)
|
||||
|
||||
# remove again
|
||||
doc = ArangoDB.log_delete("#{prefix}-remove", api + "/users-1")
|
||||
doc.headers['content-type'].should eq("application/json; charset=utf-8")
|
||||
doc.parsed_response['error'].should eq(true)
|
||||
doc.parsed_response['code'].should eq(404)
|
||||
end
|
||||
|
||||
it "remove existing user" do
|
||||
body = "{ \"username\" : \"users-1\", \"passwd\" : \"fox\", \"active\" : true, \"extra\" : { \"foo\" : true } }"
|
||||
doc = ArangoDB.log_post("#{prefix}-delete", api, :body => body)
|
||||
|
||||
# remove
|
||||
doc = ArangoDB.log_delete("#{prefix}-remove", api + "/users-1")
|
||||
doc.headers['content-type'].should eq("application/json; charset=utf-8")
|
||||
doc.parsed_response['error'].should eq(false)
|
||||
doc.parsed_response['code'].should eq(202)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
################################################################################
|
||||
## fetching users
|
||||
################################################################################
|
||||
|
||||
context "fetching users" do
|
||||
|
||||
it "no user specified" do
|
||||
doc = ArangoDB.log_get("#{prefix}-fetch", api)
|
||||
|
||||
doc.code.should eq(400)
|
||||
doc.headers['content-type'].should eq("application/json; charset=utf-8")
|
||||
doc.parsed_response['error'].should eq(true)
|
||||
doc.parsed_response['code'].should eq(400)
|
||||
doc.parsed_response['errorNum'].should eq(400)
|
||||
end
|
||||
|
||||
it "fetch non-existing user" do
|
||||
doc = ArangoDB.log_get("#{prefix}-fetch", api + "/users-16")
|
||||
|
||||
doc.code.should eq(404)
|
||||
doc.headers['content-type'].should eq("application/json; charset=utf-8")
|
||||
doc.parsed_response['error'].should eq(true)
|
||||
doc.parsed_response['code'].should eq(404)
|
||||
doc.parsed_response['errorNum'].should eq(1703)
|
||||
end
|
||||
|
||||
it "fetch user" do
|
||||
body = "{ \"username\" : \"users-2\", \"passwd\" : \"fox\", \"active\" : false, \"extra\" : { \"foo\" : true } }"
|
||||
doc = ArangoDB.log_post("#{prefix}-fetch", api, :body => body)
|
||||
|
||||
doc.code.should eq(201)
|
||||
doc.headers['content-type'].should eq("application/json; charset=utf-8")
|
||||
doc.parsed_response['error'].should eq(false)
|
||||
doc.parsed_response['code'].should eq(201)
|
||||
|
||||
doc = ArangoDB.get(api + "/users-2")
|
||||
doc.code.should eq(200)
|
||||
doc.parsed_response['error'].should eq(false)
|
||||
doc.parsed_response['code'].should eq(200)
|
||||
doc.parsed_response['user'].should eq("users-2")
|
||||
doc.parsed_response['active'].should eq(false)
|
||||
doc.parsed_response['extra'].should eq({ "foo" => true })
|
||||
doc.parsed_response.should_not have_key("passwd")
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
|
@ -21,4 +21,5 @@ rspec --color --format d \
|
|||
api-explain-spec.rb \
|
||||
api-cursor-spec.rb \
|
||||
api-statistics-spec.rb \
|
||||
api-simple-spec.rb
|
||||
api-simple-spec.rb \
|
||||
api-users-spec.rb
|
||||
|
|
|
@ -214,6 +214,7 @@ SHELL_COMMON = @top_srcdir@/js/common/tests/shell-document.js \
|
|||
@top_srcdir@/js/common/tests/shell-compactor.js \
|
||||
@top_srcdir@/js/common/tests/shell-simple-query.js \
|
||||
@top_srcdir@/js/common/tests/shell-statement.js \
|
||||
@top_srcdir@/js/common/tests/shell-crypto.js \
|
||||
@top_srcdir@/js/common/tests/shell-users.js \
|
||||
@top_srcdir@/js/common/tests/shell-index.js \
|
||||
@top_srcdir@/js/common/tests/shell-index-geo.js \
|
||||
|
|
|
@ -0,0 +1,409 @@
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief user management
|
||||
///
|
||||
/// @file
|
||||
///
|
||||
/// DISCLAIMER
|
||||
///
|
||||
/// Copyright 2012 triagens GmbH, Cologne, Germany
|
||||
///
|
||||
/// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
/// you may not use this file except in compliance with the License.
|
||||
/// You may obtain a copy of the License at
|
||||
///
|
||||
/// http://www.apache.org/licenses/LICENSE-2.0
|
||||
///
|
||||
/// Unless required by applicable law or agreed to in writing, software
|
||||
/// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
/// See the License for the specific language governing permissions and
|
||||
/// limitations under the License.
|
||||
///
|
||||
/// Copyright holder is triAGENS GmbH, Cologne, Germany
|
||||
///
|
||||
/// @author Achim Brandt
|
||||
/// @author Jan Steemann
|
||||
/// @author Copyright 2012, triAGENS GmbH, Cologne, Germany
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
var arangodb = require("org/arangodb");
|
||||
var actions = require("org/arangodb/actions");
|
||||
var users = require("org/arangodb/users");
|
||||
var ArangoError = require("org/arangodb/arango-error").ArangoError;
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- private functions
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @addtogroup ArangoAPI
|
||||
/// @{
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief fetch a user
|
||||
///
|
||||
/// @RESTHEADER{GET /_api/user,fetches a user}
|
||||
///
|
||||
/// @REST{GET /_api/user/@FA{username}}
|
||||
///
|
||||
/// Fetches data about the specified user.
|
||||
///
|
||||
/// The call will return a JSON document with at least the following attributes
|
||||
/// on success:
|
||||
///
|
||||
/// - @LIT{username}: The name of the user as a string.
|
||||
///
|
||||
/// - @LIT{active}: an optional flag that specifies whether the user is active.
|
||||
///
|
||||
/// - @LIT{extra}: an optional JSON object with arbitrary extra data about the
|
||||
/// user.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
function GET_api_user (req, res) {
|
||||
if (req.suffix.length != 1) {
|
||||
actions.resultBad(req, res, arangodb.ERROR_HTTP_BAD_PARAMETER);
|
||||
return;
|
||||
}
|
||||
|
||||
var username = decodeURIComponent(req.suffix[0]);
|
||||
try {
|
||||
var result = users.document(username);
|
||||
|
||||
actions.resultOk(req, res, actions.HTTP_OK, result)
|
||||
}
|
||||
catch (err) {
|
||||
if (err.errorNum === arangodb.errors.ERROR_USER_NOT_FOUND.code) {
|
||||
actions.resultNotFound(req, res, arangodb.errors.ERROR_USER_NOT_FOUND.code);
|
||||
}
|
||||
else {
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief create a new user
|
||||
///
|
||||
/// @RESTHEADER{POST /_api/user,creates user}
|
||||
///
|
||||
/// @REST{POST /_api/user}
|
||||
///
|
||||
/// The following data need to be passed in a JSON representation in the body of
|
||||
/// the POST request:
|
||||
///
|
||||
/// - @LIT{username}: The name of the user as a string. This is mandatory.
|
||||
///
|
||||
/// - @LIT{passwd}: The user password as a string. If no password is specified,
|
||||
/// the empty string will be used.
|
||||
///
|
||||
/// - @LIT{active}: an optional flag that specifies whether the user is active.
|
||||
/// If not specified, this will default to @LIT{true}.
|
||||
///
|
||||
/// - @LIT{extra}: an optional JSON object with arbitrary extra data about the
|
||||
/// user.
|
||||
///
|
||||
/// If the user can be added by the server, the server will respond with
|
||||
/// @LIT{HTTP 201}.
|
||||
///
|
||||
/// In case of success, the returned JSON object has the following properties:
|
||||
///
|
||||
/// - @LIT{error}: boolean flag to indicate that an error occurred (@LIT{false}
|
||||
/// in this case)
|
||||
///
|
||||
/// - @LIT{code}: the HTTP status code
|
||||
///
|
||||
/// If the JSON representation is malformed or mandatory data is missing from the
|
||||
/// request, the server will respond with @LIT{HTTP 400}.
|
||||
///
|
||||
/// The body of the response will contain a JSON object with additional error
|
||||
/// details. The object has the following attributes:
|
||||
///
|
||||
/// - @LIT{error}: boolean flag to indicate that an error occurred (@LIT{true} in this case)
|
||||
///
|
||||
/// - @LIT{code}: the HTTP status code
|
||||
///
|
||||
/// - @LIT{errorNum}: the server error number
|
||||
///
|
||||
/// - @LIT{errorMessage}: a descriptive error message
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
function POST_api_user (req, res) {
|
||||
var json = actions.getJsonBody(req, res, actions.HTTP_BAD);
|
||||
|
||||
if (json === undefined) {
|
||||
return;
|
||||
}
|
||||
|
||||
var result = users.save(json.username, json.passwd, json.active, json.extra);
|
||||
users.reload();
|
||||
|
||||
actions.resultOk(req, res, actions.HTTP_CREATED, { });
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief replace an existing user
|
||||
///
|
||||
/// @RESTHEADER{PUT /_api/user,replaces user}
|
||||
///
|
||||
/// @REST{PUT /_api/user/@FA{username}}
|
||||
///
|
||||
/// Replaces the data of an existing user. The name of an existing user must
|
||||
/// be specified in @FA{username}.
|
||||
///
|
||||
/// The following data can to be passed in a JSON representation in the body of
|
||||
/// the POST request:
|
||||
///
|
||||
/// - @LIT{passwd}: The user password as a string. Specifying a password is
|
||||
/// mandatory, but the empty string is allowed for passwords.
|
||||
///
|
||||
/// - @LIT{active}: an optional flag that specifies whether the user is active.
|
||||
/// If not specified, this will default to @LIT{true}.
|
||||
///
|
||||
/// - @LIT{extra}: an optional JSON object with arbitrary extra data about the
|
||||
/// user.
|
||||
///
|
||||
/// If the user can be replaced by the server, the server will respond with
|
||||
/// @LIT{HTTP 200}.
|
||||
///
|
||||
/// In case of success, the returned JSON object has the following properties:
|
||||
///
|
||||
/// - @LIT{error}: boolean flag to indicate that an error occurred (@LIT{false}
|
||||
/// in this case)
|
||||
///
|
||||
/// - @LIT{code}: the HTTP status code
|
||||
///
|
||||
/// If the JSON representation is malformed or mandatory data is missing from the
|
||||
/// request, the server will respond with @LIT{HTTP 400}. If the specified user
|
||||
/// does not exist, the server will respond with @LIT{HTTP 404}.
|
||||
///
|
||||
/// The body of the response will contain a JSON object with additional error
|
||||
/// details. The object has the following attributes:
|
||||
///
|
||||
/// - @LIT{error}: boolean flag to indicate that an error occurred (@LIT{true} in this case)
|
||||
///
|
||||
/// - @LIT{code}: the HTTP status code
|
||||
///
|
||||
/// - @LIT{errorNum}: the server error number
|
||||
///
|
||||
/// - @LIT{errorMessage}: a descriptive error message
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
function PUT_api_user (req, res) {
|
||||
if (req.suffix.length != 1) {
|
||||
actions.resultBad(req, res, arangodb.ERROR_HTTP_BAD_PARAMETER);
|
||||
return;
|
||||
}
|
||||
|
||||
var username = decodeURIComponent(req.suffix[0]);
|
||||
|
||||
var json = actions.getJsonBody(req, res, actions.HTTP_BAD);
|
||||
|
||||
if (json === undefined) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
var result = users.replace(username, json.passwd, json.active, json.extra);
|
||||
users.reload();
|
||||
|
||||
actions.resultOk(req, res, actions.HTTP_OK, { });
|
||||
}
|
||||
catch (err) {
|
||||
if (err.errorNum === arangodb.errors.ERROR_USER_NOT_FOUND.code) {
|
||||
actions.resultNotFound(req, res, arangodb.errors.ERROR_USER_NOT_FOUND.code);
|
||||
}
|
||||
else {
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief partially update an existing user
|
||||
///
|
||||
/// @RESTHEADER{PATCH /_api/user,updates user}
|
||||
///
|
||||
/// @REST{PATCH /_api/user/@FA{username}}
|
||||
///
|
||||
/// Partially updates the data of an existing user. The name of an existing user
|
||||
/// must be specified in @FA{username}.
|
||||
///
|
||||
/// The following data can be passed in a JSON representation in the body of
|
||||
/// the POST request:
|
||||
///
|
||||
/// - @LIT{passwd}: The user password as a string. Specifying a password is
|
||||
/// optional. If not specified, the previously existing value will not be
|
||||
/// modified.
|
||||
///
|
||||
/// - @LIT{active}: an optional flag that specifies whether the user is active.
|
||||
/// If not specified, the previously existing value will not be modified.
|
||||
///
|
||||
/// - @LIT{extra}: an optional JSON object with arbitrary extra data about the
|
||||
/// user. If not specified, the previously existing value will not be modified.
|
||||
///
|
||||
/// If the user can be updated by the server, the server will respond with
|
||||
/// @LIT{HTTP 200}.
|
||||
///
|
||||
/// In case of success, the returned JSON object has the following properties:
|
||||
///
|
||||
/// - @LIT{error}: boolean flag to indicate that an error occurred (@LIT{false}
|
||||
/// in this case)
|
||||
///
|
||||
/// - @LIT{code}: the HTTP status code
|
||||
///
|
||||
/// If the JSON representation is malformed or mandatory data is missing from the
|
||||
/// request, the server will respond with @LIT{HTTP 400}. If the specified user
|
||||
/// does not exist, the server will respond with @LIT{HTTP 404}.
|
||||
///
|
||||
/// The body of the response will contain a JSON object with additional error
|
||||
/// details. The object has the following attributes:
|
||||
///
|
||||
/// - @LIT{error}: boolean flag to indicate that an error occurred (@LIT{true} in this case)
|
||||
///
|
||||
/// - @LIT{code}: the HTTP status code
|
||||
///
|
||||
/// - @LIT{errorNum}: the server error number
|
||||
///
|
||||
/// - @LIT{errorMessage}: a descriptive error message
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
function PATCH_api_user (req, res) {
|
||||
if (req.suffix.length != 1) {
|
||||
actions.resultBad(req, res, arangodb.ERROR_HTTP_BAD_PARAMETER);
|
||||
return;
|
||||
}
|
||||
|
||||
var username = decodeURIComponent(req.suffix[0]);
|
||||
|
||||
var json = actions.getJsonBody(req, res, actions.HTTP_BAD);
|
||||
|
||||
if (json === undefined) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
var result = users.update(username, json.passwd, json.active, json.extra);
|
||||
users.reload();
|
||||
actions.resultOk(req, res, actions.HTTP_OK, { });
|
||||
}
|
||||
catch (err) {
|
||||
if (err.errorNum === arangodb.errors.ERROR_USER_NOT_FOUND.code) {
|
||||
actions.resultNotFound(req, res, arangodb.errors.ERROR_USER_NOT_FOUND.code);
|
||||
}
|
||||
else {
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief remove an existing user
|
||||
///
|
||||
/// @RESTHEADER{DELETE /_api/user,removes a user}
|
||||
///
|
||||
/// @REST{DELETE /_api/user/@FA{username}}
|
||||
///
|
||||
/// Removes an existing user, identified by @FA{username}.
|
||||
///
|
||||
/// If the user can be removed by the server, the server will respond with
|
||||
/// @LIT{HTTP 202}.
|
||||
///
|
||||
/// In case of success, the returned JSON object has the following properties:
|
||||
///
|
||||
/// - @LIT{error}: boolean flag to indicate that an error occurred (@LIT{false}
|
||||
/// in this case)
|
||||
///
|
||||
/// - @LIT{code}: the HTTP status code
|
||||
///
|
||||
/// If the JSON representation is malformed or mandatory data is missing from the
|
||||
/// request, the server will respond with @LIT{HTTP 400}. If the specified user
|
||||
/// does not exist, the server will respond with @LIT{HTTP 404}.
|
||||
///
|
||||
/// The body of the response will contain a JSON object with additional error
|
||||
/// details. The object has the following attributes:
|
||||
///
|
||||
/// - @LIT{error}: boolean flag to indicate that an error occurred (@LIT{true} in this case)
|
||||
///
|
||||
/// - @LIT{code}: the HTTP status code
|
||||
///
|
||||
/// - @LIT{errorNum}: the server error number
|
||||
///
|
||||
/// - @LIT{errorMessage}: a descriptive error message
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
function DELETE_api_user (req, res) {
|
||||
if (req.suffix.length != 1) {
|
||||
actions.resultBad(req, res, arangodb.ERROR_HTTP_BAD_PARAMETER);
|
||||
return;
|
||||
}
|
||||
|
||||
var username = decodeURIComponent(req.suffix[0]);
|
||||
try {
|
||||
var result = users.remove(username);
|
||||
users.reload();
|
||||
actions.resultOk(req, res, actions.HTTP_ACCEPTED, { });
|
||||
}
|
||||
catch (err) {
|
||||
if (err.errorNum === arangodb.errors.ERROR_USER_NOT_FOUND.code) {
|
||||
actions.resultNotFound(req, res, arangodb.errors.ERROR_USER_NOT_FOUND.code);
|
||||
}
|
||||
else {
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- initialiser
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief user actions gateway
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
actions.defineHttp({
|
||||
url : "_api/user",
|
||||
context : "api",
|
||||
|
||||
callback : function (req, res) {
|
||||
try {
|
||||
switch (req.requestType) {
|
||||
case actions.GET:
|
||||
GET_api_user(req, res);
|
||||
break;
|
||||
|
||||
case actions.POST:
|
||||
POST_api_user(req, res);
|
||||
break;
|
||||
|
||||
case actions.PUT:
|
||||
PUT_api_user(req, res);
|
||||
break;
|
||||
|
||||
case actions.PATCH:
|
||||
PATCH_api_user(req, res);
|
||||
break;
|
||||
|
||||
case actions.DELETE:
|
||||
DELETE_api_user(req, res);
|
||||
break;
|
||||
|
||||
default:
|
||||
actions.resultUnsupported(req, res);
|
||||
}
|
||||
}
|
||||
catch (err) {
|
||||
actions.resultException(req, res, err);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @}
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Local Variables:
|
||||
// mode: outline-minor
|
||||
// outline-regexp: "^\\(/// @brief\\|/// @addtogroup\\|// --SECTION--\\|/// @page\\|/// @}\\)"
|
||||
// End:
|
|
@ -1,12 +1,13 @@
|
|||
/*jslint indent: 2, nomen: true, maxlen: 100, sloppy: true, vars: true, white: true, plusplus: true, nonpropdel: true, proto: true */
|
||||
/*global require, module, Module, FS_MOVE, FS_REMOVE, FS_EXISTS, FS_IS_DIRECTORY, FS_LIST_TREE,
|
||||
SYS_EXECUTE, SYS_LOAD, SYS_LOG, SYS_LOG_LEVEL, SYS_OUTPUT, SYS_PROCESS_STAT, SYS_READ,
|
||||
SYS_SPRINTF, SYS_TIME, SYS_START_PAGER, SYS_STOP_PAGER, SYS_SHA256, SYS_WAIT, SYS_GETLINE,
|
||||
SYS_PARSE, SYS_SAVE, SYS_IMPORT_CSV_FILE, SYS_IMPORT_JSON_FILE, SYS_PROCESS_CSV_FILE,
|
||||
SYS_PROCESS_JSON_FILE, ARANGO_QUIET, MODULES_PATH, COLORS, COLOR_OUTPUT, COLOR_OUTPUT_RESET,
|
||||
COLOR_BRIGHT, COLOR_BLACK, COLOR_BOLD_BLACK, COLOR_BLINK, COLOR_BLUE, COLOR_BOLD_BLUE,
|
||||
COLOR_BOLD_GREEN, COLOR_RED, COLOR_BOLD_RED, COLOR_GREEN, COLOR_WHITE, COLOR_BOLD_WHITE,
|
||||
COLOR_YELLOW, COLOR_BOLD_YELLOW, PRETTY_PRINT, VALGRIND, HAS_ICU, VERSION, UPGRADE */
|
||||
SYS_EXECUTE, SYS_LOAD, SYS_LOG, SYS_LOG_LEVEL, SYS_MD5, SYS_OUTPUT, SYS_PROCESS_STAT, SYS_RAND,
|
||||
SYS_READ, SYS_SPRINTF, SYS_TIME, SYS_START_PAGER, SYS_STOP_PAGER, SYS_SHA256, SYS_WAIT,
|
||||
SYS_GETLINE, SYS_PARSE, SYS_SAVE, SYS_IMPORT_CSV_FILE, SYS_IMPORT_JSON_FILE,
|
||||
SYS_PROCESS_CSV_FILE, SYS_PROCESS_JSON_FILE, ARANGO_QUIET, MODULES_PATH, COLORS, COLOR_OUTPUT,
|
||||
COLOR_OUTPUT_RESET, COLOR_BRIGHT, COLOR_BLACK, COLOR_BOLD_BLACK, COLOR_BLINK, COLOR_BLUE,
|
||||
COLOR_BOLD_BLUE, COLOR_BOLD_GREEN, COLOR_RED, COLOR_BOLD_RED, COLOR_GREEN, COLOR_WHITE,
|
||||
COLOR_BOLD_WHITE, COLOR_YELLOW, COLOR_BOLD_YELLOW, PRETTY_PRINT, VALGRIND, HAS_ICU, VERSION,
|
||||
UPGRADE */
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief module "internal"
|
||||
|
@ -76,6 +77,11 @@
|
|||
internal.logLevel = SYS_LOG_LEVEL;
|
||||
delete SYS_LOG_LEVEL;
|
||||
}
|
||||
|
||||
if (typeof SYS_MD5 !== "undefined") {
|
||||
internal.md5 = SYS_MD5;
|
||||
delete SYS_MD5;
|
||||
}
|
||||
|
||||
if (typeof SYS_OUTPUT !== "undefined") {
|
||||
internal.stdOutput = SYS_OUTPUT;
|
||||
|
@ -92,6 +98,11 @@
|
|||
internal.processStat = SYS_PROCESS_STAT;
|
||||
delete SYS_PROCESS_STAT;
|
||||
}
|
||||
|
||||
if (typeof SYS_RAND !== "undefined") {
|
||||
internal.rand = SYS_RAND;
|
||||
delete SYS_RAND;
|
||||
}
|
||||
|
||||
if (typeof SYS_READ !== "undefined") {
|
||||
internal.read = SYS_READ;
|
||||
|
@ -798,22 +809,6 @@
|
|||
}
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief encode password using SHA256
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
internal.encodePassword = function (password) {
|
||||
var salt;
|
||||
var encoded;
|
||||
|
||||
salt = internal.sha256("time:" + internal.time());
|
||||
salt = salt.substr(0,8);
|
||||
|
||||
encoded = "$1$" + salt + "$" + internal.sha256(salt + password);
|
||||
|
||||
return encoded;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief extends a prototype
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -0,0 +1,101 @@
|
|||
/*jslint indent: 2, nomen: true, maxlen: 100, sloppy: true, vars: true, white: true, plusplus: true */
|
||||
/*global require, exports */
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief Some crypto functions
|
||||
///
|
||||
/// @file
|
||||
///
|
||||
/// DISCLAIMER
|
||||
///
|
||||
/// Copyright 2012 triagens GmbH, Cologne, Germany
|
||||
///
|
||||
/// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
/// you may not use this file except in compliance with the License.
|
||||
/// You may obtain a copy of the License at
|
||||
///
|
||||
/// http://www.apache.org/licenses/LICENSE-2.0
|
||||
///
|
||||
/// Unless required by applicable law or agreed to in writing, software
|
||||
/// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
/// See the License for the specific language governing permissions and
|
||||
/// limitations under the License.
|
||||
///
|
||||
/// Copyright holder is triAGENS GmbH, Cologne, Germany
|
||||
///
|
||||
/// @author Jan Steemann
|
||||
/// @author Copyright 2013, triAGENS GmbH, Cologne, Germany
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
var internal = require("internal");
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- RANDOM
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- public methods
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @addtogroup Random
|
||||
/// @{
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief generate a random number
|
||||
///
|
||||
/// the value returned might be positive or negative or even 0.
|
||||
/// if random number generation fails, then undefined is returned
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
exports.rand = function (value) {
|
||||
return internal.rand();
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @}
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- HASHES
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- public methods
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @addtogroup Hashes
|
||||
/// @{
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief apply an MD5 hash
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
exports.md5 = function (value) {
|
||||
return internal.md5(value);
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief apply an SHA 256 hash
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
exports.sha256 = function (value) {
|
||||
return internal.sha256(value);
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @}
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- END-OF-FILE
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// Local Variables:
|
||||
// mode: outline-minor
|
||||
// outline-regexp: "/// @brief\\|/// @addtogroup\\|// --SECTION--\\|/// @}\\|/\\*jslint"
|
||||
// End:
|
|
@ -28,11 +28,11 @@
|
|||
/// @author Copyright 2012, triAGENS GmbH, Cologne, Germany
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
var internal = require("internal"); // OK: encodePassword, reloadAuth
|
||||
var internal = require("internal"); // OK: reloadAuth, time
|
||||
|
||||
var encodePassword = internal.encodePassword;
|
||||
var reloadAuth = internal.reloadAuth;
|
||||
var arangodb = require("org/arangodb");
|
||||
var crypto = require("org/arangodb/crypto");
|
||||
var db = arangodb.db;
|
||||
var ArangoError = require("org/arangodb/arango-error").ArangoError;
|
||||
|
||||
|
@ -49,6 +49,30 @@ var ArangoError = require("org/arangodb/arango-error").ArangoError;
|
|||
/// @{
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief encode password using SHA256
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
var encodePassword = function (password) {
|
||||
var salt;
|
||||
var encoded;
|
||||
|
||||
var random = crypto.rand();
|
||||
if (random === undefined) {
|
||||
random = "time:" + internal.time();
|
||||
}
|
||||
else {
|
||||
random = "random:" + random;
|
||||
}
|
||||
|
||||
salt = crypto.sha256(random);
|
||||
salt = salt.substr(0,8);
|
||||
|
||||
encoded = "$1$" + salt + "$" + crypto.sha256(salt + password);
|
||||
|
||||
return encoded;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief validate a username
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -112,14 +136,16 @@ var getStorage = function () {
|
|||
/// @fn JSF_saveUser
|
||||
/// @brief create a new user
|
||||
///
|
||||
/// @FUN{@FA{users}.save(@FA{username}, @FA{passwd})}
|
||||
/// @FUN{@FA{users}.save(@FA{username}, @FA{passwd}, @FA{active}, @FA{extra})}
|
||||
///
|
||||
/// This will create a new ArangoDB user.
|
||||
/// The username must be a string and contain only the letters a-z (lower or
|
||||
/// upper case), the digits 0-9, the dash or the underscore symbol.
|
||||
/// This will create a new ArangoDB user. The username must be specified and
|
||||
/// must not be empty.
|
||||
///
|
||||
/// The password must be given as a string, too, but can be left empty if
|
||||
/// required.
|
||||
///
|
||||
/// If the @FA{active} attribute is not specified, it defaults to @LIT{true}.
|
||||
/// The @FA{extra} attribute can be used to save custom data with the user.
|
||||
///
|
||||
/// This method will fail if either the username or the passwords are not
|
||||
/// specified or given in a wrong format, or there already exists a user with
|
||||
|
@ -135,7 +161,7 @@ var getStorage = function () {
|
|||
/// @TINYEXAMPLE{user-save,saving a new user}
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
exports.save = function (username, passwd) {
|
||||
exports.save = function (username, passwd, active, extra) {
|
||||
if (passwd === null || passwd === undefined) {
|
||||
passwd = "";
|
||||
}
|
||||
|
@ -147,9 +173,24 @@ exports.save = function (username, passwd) {
|
|||
var users = getStorage();
|
||||
var user = users.firstExample({ user: username });
|
||||
|
||||
if (active === undefined || active === null) {
|
||||
// this is the default value for active
|
||||
active = true;
|
||||
}
|
||||
|
||||
if (user === null) {
|
||||
var hash = encodePassword(passwd);
|
||||
return users.save({ user: username, password: hash, active: true });
|
||||
var data = {
|
||||
user: username,
|
||||
password: hash,
|
||||
active: active
|
||||
};
|
||||
|
||||
if (extra !== undefined) {
|
||||
data.extra = extra;
|
||||
}
|
||||
|
||||
return users.save(data);
|
||||
}
|
||||
|
||||
var err = new ArangoError();
|
||||
|
@ -161,19 +202,91 @@ exports.save = function (username, passwd) {
|
|||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @fn JSF_replaceUser
|
||||
/// @brief update an existing user
|
||||
/// @brief replace an existing user
|
||||
///
|
||||
/// @FUN{@FA{users}.replace(@FA{username}, @FA{passwd})}
|
||||
/// @FUN{@FA{users}.replace(@FA{username}, @FA{passwd}, @FA{active}, @FA{extra})}
|
||||
///
|
||||
/// This will update an existing ArangoDB user with a new password.
|
||||
/// This will look up an existing ArangoDB user and replace its user data.
|
||||
///
|
||||
/// The username must be a string and contain only the letters a-z (lower or
|
||||
/// upper case), the digits 0-9, the dash or the underscore symbol. The user
|
||||
/// must already exist in the database.
|
||||
/// The username must be specified, and a user with the specified name must
|
||||
/// already exist in the database.
|
||||
///
|
||||
/// The password must be given as a string, too, but can be left empty if
|
||||
/// required.
|
||||
///
|
||||
/// If the @FA{active} attribute is not specified, it defaults to @LIT{true}.
|
||||
/// The @FA{extra} attribute can be used to save custom data with the user.
|
||||
///
|
||||
/// This method will fail if either the username or the passwords are not
|
||||
/// specified or given in a wrong format, or if the specified user cannot be
|
||||
/// found in the database.
|
||||
///
|
||||
/// The replace is effective only after the server is either restarted
|
||||
/// or the server authentication cache is reloaded (see @ref JSF_reloadUsers).
|
||||
///
|
||||
/// Note: this function will not work from within the web interface
|
||||
///
|
||||
/// @EXAMPLES
|
||||
///
|
||||
/// @TINYEXAMPLE{user-replace,replacing an existing user}
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
exports.replace = function (username, passwd, active, extra) {
|
||||
if (passwd === null || passwd === undefined) {
|
||||
passwd = "";
|
||||
}
|
||||
|
||||
// validate input
|
||||
validateName(username);
|
||||
validatePassword(passwd);
|
||||
|
||||
var users = getStorage();
|
||||
var user = users.firstExample({ user: username });
|
||||
|
||||
if (active === undefined || active === null) {
|
||||
// this is the default
|
||||
active = true;
|
||||
}
|
||||
|
||||
if (user === null) {
|
||||
var err = new ArangoError();
|
||||
err.errorNum = arangodb.errors.ERROR_USER_NOT_FOUND.code;
|
||||
err.errorMessage = arangodb.errors.ERROR_USER_NOT_FOUND.message;
|
||||
|
||||
throw err;
|
||||
}
|
||||
|
||||
var hash = encodePassword(passwd);
|
||||
var data = {
|
||||
user: username,
|
||||
password: hash,
|
||||
active: active
|
||||
};
|
||||
if (extra !== undefined) {
|
||||
data.extra = extra;
|
||||
}
|
||||
|
||||
return users.replace(user, data);
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @fn JSF_updateUser
|
||||
/// @brief update an existing user
|
||||
///
|
||||
/// @FUN{@FA{users}.update(@FA{username}, @FA{passwd}, @FA{active}, @FA{extra})}
|
||||
///
|
||||
/// This will update an existing ArangoDB user with a new password and other
|
||||
/// data.
|
||||
///
|
||||
/// The username must be specified and the user must already exist in the
|
||||
/// database.
|
||||
///
|
||||
/// The password must be given as a string, too, but can be left empty if
|
||||
/// required.
|
||||
///
|
||||
/// If the @FA{active} attribute is not specified, the current value saved for
|
||||
/// the user will not be changed. The same is true for the @FA{extra} attribute.
|
||||
///
|
||||
/// This method will fail if either the username or the passwords are not
|
||||
/// specified or given in a wrong format, or if the specified user cannot be
|
||||
/// found in the database.
|
||||
|
@ -187,20 +300,17 @@ exports.save = function (username, passwd) {
|
|||
///
|
||||
/// @TINYEXAMPLE{user-replace,replacing an existing user}
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
exports.replace =
|
||||
exports.update = function (username, passwd) {
|
||||
if (passwd === null || passwd === undefined) {
|
||||
passwd = "";
|
||||
}
|
||||
|
||||
exports.update = function (username, passwd, active, extra) {
|
||||
// validate input
|
||||
validateName(username);
|
||||
validatePassword(passwd);
|
||||
if (passwd !== undefined) {
|
||||
validatePassword(passwd);
|
||||
}
|
||||
|
||||
var users = getStorage();
|
||||
var user = users.firstExample({ user: username });
|
||||
|
||||
|
||||
if (user === null) {
|
||||
var err = new ArangoError();
|
||||
err.errorNum = arangodb.errors.ERROR_USER_NOT_FOUND.code;
|
||||
|
@ -209,10 +319,20 @@ exports.update = function (username, passwd) {
|
|||
throw err;
|
||||
}
|
||||
|
||||
var hash = encodePassword(passwd);
|
||||
var data = user.shallowCopy;
|
||||
data.password = hash;
|
||||
return users.replace(user, data);
|
||||
|
||||
if (passwd !== undefined) {
|
||||
var hash = encodePassword(passwd);
|
||||
data.password = hash;
|
||||
}
|
||||
if (active !== undefined && active !== null) {
|
||||
data.active = active;
|
||||
}
|
||||
if (extra !== undefined) {
|
||||
data.extra = extra;
|
||||
}
|
||||
|
||||
return users.update(user, data);
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -223,9 +343,8 @@ exports.update = function (username, passwd) {
|
|||
///
|
||||
/// Removes an existing ArangoDB user from the database.
|
||||
///
|
||||
/// The username must be a string and contain only the letters a-z (lower or
|
||||
/// upper case), the digits 0-9, the dash or the underscore symbol. The user
|
||||
/// must already exist in the database.
|
||||
/// The username must be a string and the specified user must exist in the
|
||||
/// database.
|
||||
///
|
||||
/// This method will fail if the user cannot be found in the database.
|
||||
///
|
||||
|
@ -257,6 +376,39 @@ exports.remove = function (username) {
|
|||
return users.remove(user._id);
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @fn JSF_documentUser
|
||||
/// @brief get an existing user
|
||||
///
|
||||
/// @FUN{@FA{users}.document(@FA{username})}
|
||||
///
|
||||
/// Fetches an existing ArangoDB user from the database.
|
||||
///
|
||||
/// This method will fail if the user cannot be found in the database.
|
||||
///
|
||||
/// Note: this function will not work from within the web interface
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
exports.document = function (username) {
|
||||
// validate name
|
||||
validateName(username);
|
||||
|
||||
var users = getStorage();
|
||||
var user = users.firstExample({ user: username });
|
||||
|
||||
if (user === null) {
|
||||
var err = new ArangoError();
|
||||
err.errorNum = arangodb.errors.ERROR_USER_NOT_FOUND.code;
|
||||
err.errorMessage = arangodb.errors.ERROR_USER_NOT_FOUND.message;
|
||||
|
||||
throw err;
|
||||
}
|
||||
|
||||
delete user.passwd;
|
||||
|
||||
return user;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief reloads the user authentication data
|
||||
///
|
||||
|
|
|
@ -0,0 +1,139 @@
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief test the crypto interface
|
||||
///
|
||||
/// @file
|
||||
///
|
||||
/// DISCLAIMER
|
||||
///
|
||||
/// Copyright 2010-2012 triagens GmbH, Cologne, Germany
|
||||
///
|
||||
/// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
/// you may not use this file except in compliance with the License.
|
||||
/// You may obtain a copy of the License at
|
||||
///
|
||||
/// http://www.apache.org/licenses/LICENSE-2.0
|
||||
///
|
||||
/// Unless required by applicable law or agreed to in writing, software
|
||||
/// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
/// See the License for the specific language governing permissions and
|
||||
/// limitations under the License.
|
||||
///
|
||||
/// Copyright holder is triAGENS GmbH, Cologne, Germany
|
||||
///
|
||||
/// @author Jan Steemann
|
||||
/// @author Copyright 2013, triAGENS GmbH, Cologne, Germany
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
var jsunity = require("jsunity");
|
||||
var crypto = require("org/arangodb/crypto");
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- crypto methods
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief test suite
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
function CryptoSuite () {
|
||||
return {
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief test md5, invalid values
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
testMd5Invalid : function () {
|
||||
[ undefined, null, true, false, 0, 1, -1, 32.5, [ ], { } ].forEach(function (value) {
|
||||
try {
|
||||
crypto.md5(value);
|
||||
fail();
|
||||
}
|
||||
catch (err) {
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief test md5
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
testMd5 : function () {
|
||||
var data = [
|
||||
[ "", "d41d8cd98f00b204e9800998ecf8427e" ],
|
||||
[ " ", "7215ee9c7d9dc229d2921a40e899ec5f" ],
|
||||
[ "arangodb", "335889e69e03cefd041babef1b02a0b8" ],
|
||||
[ "Arangodb", "0862bc79ec789143f75e3282df98c8f4" ],
|
||||
[ "ArangoDB is a database", "b88ddc26cfa3a652fdd8bf8e8c069540" ]
|
||||
];
|
||||
|
||||
data.forEach(function (value) {
|
||||
assertEqual(value[1], crypto.md5(value[0]));
|
||||
});
|
||||
},
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief test sha256, invalid values
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
testSha256Invalid : function () {
|
||||
[ undefined, null, true, false, 0, 1, -1, 32.5, [ ], { } ].forEach(function (value) {
|
||||
try {
|
||||
crypto.sha256(value);
|
||||
fail();
|
||||
}
|
||||
catch (err) {
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief test sha256
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
testSha256 : function () {
|
||||
var data = [
|
||||
[ "", "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" ],
|
||||
[ " ", "36a9e7f1c95b82ffb99743e0c5c4ce95d83c9a430aac59f84ef3cbfab6145068"],
|
||||
[ "arangodb", "d0a274654772fa104df32ff457ff0a432f2dfad18e7c3146fab3c807f2ed86e5" ],
|
||||
[ "Arangodb", "38579e73fd7435de7db93028a1b340be77445b46c94dff013c05c696ccae259c" ],
|
||||
[ "ArangoDB is a database", "00231e8f9c0a617426ae51e4e230a1b25f6d5b82c10fccc835b514142f235f31" ]
|
||||
];
|
||||
|
||||
data.forEach(function (value) {
|
||||
assertEqual(value[1], crypto.sha256(value[0]));
|
||||
});
|
||||
},
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief test random
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
testRandom : function () {
|
||||
var i;
|
||||
|
||||
for (i = 0; i < 100; ++i) {
|
||||
assertTrue(crypto.rand() != 0);
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- main
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief executes the test suite
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
jsunity.run(CryptoSuite);
|
||||
|
||||
return jsunity.done();
|
||||
|
||||
// Local Variables:
|
||||
// mode: outline-minor
|
||||
// outline-regexp: "^\\(/// @brief\\|/// @addtogroup\\|// --SECTION--\\|/// @page\\|/// @}\\)"
|
||||
// End:
|
||||
|
|
@ -45,6 +45,7 @@
|
|||
(function() {
|
||||
var internal = require("internal");
|
||||
var console = require("console");
|
||||
var userManager = require("org/arangodb/users");
|
||||
var db = internal.db;
|
||||
|
||||
// path to the VERSION file
|
||||
|
@ -147,7 +148,7 @@
|
|||
|
||||
if (users.count() === 0) {
|
||||
// only add account if user has not created his/her own accounts already
|
||||
users.save({ user: "root", password: internal.encodePassword(""), active: true });
|
||||
userManager.save("root", "", true);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
#include <openssl/sha.h>
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/hmac.h>
|
||||
#include <openssl/rand.h>
|
||||
|
||||
#include <Basics/RandomGenerator.h>
|
||||
#include <Basics/StringUtils.h>
|
||||
|
@ -130,7 +131,6 @@ namespace triagens {
|
|||
}
|
||||
|
||||
|
||||
|
||||
void sslSHA256 (char const* inputStr, char*& outputStr, size_t& outputLen) {
|
||||
sslSHA256(inputStr, strlen(inputStr), outputStr, outputLen);
|
||||
}
|
||||
|
@ -180,9 +180,8 @@ namespace triagens {
|
|||
void sslBASE64 (char const* inputStr, char*& outputStr, size_t& outputLen) {
|
||||
sslBASE64(inputStr, strlen(inputStr), outputStr, outputLen);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
string sslHMAC (char const* key, char const* message, size_t messageLen) {
|
||||
const EVP_MD * evp_md = EVP_sha256();
|
||||
unsigned char* md = (unsigned char*) TRI_SystemAllocate(EVP_MAX_MD_SIZE + 1, false);
|
||||
|
@ -212,7 +211,30 @@ namespace triagens {
|
|||
return false;
|
||||
}
|
||||
|
||||
|
||||
int sslRand (uint64_t* value) {
|
||||
if (! RAND_pseudo_bytes((unsigned char *) value, sizeof(uint64_t))) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sslRand (int64_t* value) {
|
||||
if (! RAND_pseudo_bytes((unsigned char *) value, sizeof(int64_t))) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sslRand (int32_t* value) {
|
||||
if (! RAND_pseudo_bytes((unsigned char *) value, sizeof(int32_t))) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void salt64 (uint64_t& result) {
|
||||
string salt = SaltGenerator.random(8);
|
||||
|
|
|
@ -99,12 +99,12 @@ namespace triagens {
|
|||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void sslHEX (char const* inputStr, char*& outputStr, size_t& outputLen);
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
/// @brief BASE64
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void sslBAE64 (char const* inputStr, const size_t length, char*& outputStr, size_t& outputLen);
|
||||
void sslBASE64 (char const* inputStr, const size_t length, char*& outputStr, size_t& outputLen);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
/// @brief BASE64
|
||||
|
@ -123,12 +123,36 @@ namespace triagens {
|
|||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool verifyHMAC (char const* challenge, char const* secret, size_t secretLen, char const* response, size_t responseLen);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
/// @brief generate a random number using OpenSsl
|
||||
///
|
||||
/// will return 0 on success, and != 0 on error
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int sslRand (uint64_t*);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
/// @brief generate a random number using OpenSsl
|
||||
///
|
||||
/// will return 0 on success, and != 0 on error
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int sslRand (int64_t*);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
/// @brief generate a random number using OpenSsl
|
||||
///
|
||||
/// will return 0 on success, and != 0 on error
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int sslRand (int32_t*);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
/// @brief salt
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void salt64 (uint64_t& saltInt);
|
||||
void salt64 (uint64_t& saltInt);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
/// @brief salt
|
||||
|
|
|
@ -619,6 +619,46 @@ static v8::Handle<v8::Value> JS_LogLevel (v8::Arguments const& argv) {
|
|||
return scope.Close(v8::String::New(TRI_LogLevelLogging()));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief md5 sum
|
||||
///
|
||||
/// @FUN{internal.md5(@FA{text})}
|
||||
///
|
||||
/// Computes an md5 for the @FA{text}.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static v8::Handle<v8::Value> JS_Md5 (v8::Arguments const& argv) {
|
||||
v8::HandleScope scope;
|
||||
|
||||
// extract arguments
|
||||
if (argv.Length() != 1 || ! argv[0]->IsString()) {
|
||||
return scope.Close(v8::ThrowException(v8::String::New("usage: md5(<text>)")));
|
||||
}
|
||||
|
||||
string key = TRI_ObjectToString(argv[0]);
|
||||
|
||||
// create md5
|
||||
char* hash = 0;
|
||||
size_t hashLen;
|
||||
|
||||
SslInterface::sslMD5(key.c_str(), key.size(), hash, hashLen);
|
||||
|
||||
// as hex
|
||||
char* hex = 0;
|
||||
size_t hexLen;
|
||||
|
||||
SslInterface::sslHEX(hash, hashLen, hex, hexLen);
|
||||
|
||||
delete[] hash;
|
||||
|
||||
// and return
|
||||
v8::Handle<v8::String> hashStr = v8::String::New(hex, hexLen);
|
||||
|
||||
delete[] hex;
|
||||
|
||||
return scope.Close(hashStr);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief renames a file
|
||||
///
|
||||
|
@ -742,6 +782,46 @@ static v8::Handle<v8::Value> JS_ProcessStat (v8::Arguments const& argv) {
|
|||
return scope.Close(result);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief generate a random number using OpenSSL
|
||||
///
|
||||
/// @FUN{internal.rand()}
|
||||
///
|
||||
/// Generates a random number
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static v8::Handle<v8::Value> JS_Rand (v8::Arguments const& argv) {
|
||||
v8::HandleScope scope;
|
||||
|
||||
// check arguments
|
||||
if (argv.Length() != 0) {
|
||||
return scope.Close(v8::ThrowException(v8::String::New("usage: rand()")));
|
||||
}
|
||||
|
||||
int iterations = 0;
|
||||
while (iterations++ < 5) {
|
||||
int32_t value;
|
||||
int result = SslInterface::sslRand(&value);
|
||||
|
||||
if (result != 0) {
|
||||
// error
|
||||
break;
|
||||
}
|
||||
|
||||
// no error, now check what random number was produced
|
||||
|
||||
if (value != 0) {
|
||||
// a number != 0 was produced. that is sufficient
|
||||
return scope.Close(v8::Number::New(value));
|
||||
}
|
||||
|
||||
// we don't want to return 0 as the result, so we try again
|
||||
}
|
||||
|
||||
// we failed to produce a valid random number
|
||||
return scope.Close(v8::Undefined());
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief reads in a file
|
||||
///
|
||||
|
@ -962,14 +1042,14 @@ static v8::Handle<v8::Value> JS_SPrintF (v8::Arguments const& argv) {
|
|||
///
|
||||
/// @FUN{internal.sha256(@FA{text})}
|
||||
///
|
||||
/// Computes a sha256 for the @FA{text}.
|
||||
/// Computes an sha256 for the @FA{text}.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static v8::Handle<v8::Value> JS_Sha256 (v8::Arguments const& argv) {
|
||||
v8::HandleScope scope;
|
||||
|
||||
// extract arguments
|
||||
if (argv.Length() != 1) {
|
||||
if (argv.Length() != 1 || ! argv[0]->IsString()) {
|
||||
return scope.Close(v8::ThrowException(v8::String::New("usage: sha256(<text>)")));
|
||||
}
|
||||
|
||||
|
@ -1398,9 +1478,11 @@ void TRI_InitV8Utils (v8::Handle<v8::Context> context, string const& path) {
|
|||
TRI_AddGlobalFunctionVocbase(context, "SYS_LOAD", JS_Load);
|
||||
TRI_AddGlobalFunctionVocbase(context, "SYS_LOG", JS_Log);
|
||||
TRI_AddGlobalFunctionVocbase(context, "SYS_LOG_LEVEL", JS_LogLevel);
|
||||
TRI_AddGlobalFunctionVocbase(context, "SYS_MD5", JS_Md5);
|
||||
TRI_AddGlobalFunctionVocbase(context, "SYS_OUTPUT", JS_Output);
|
||||
TRI_AddGlobalFunctionVocbase(context, "SYS_PARSE", JS_Parse);
|
||||
TRI_AddGlobalFunctionVocbase(context, "SYS_PROCESS_STAT", JS_ProcessStat);
|
||||
TRI_AddGlobalFunctionVocbase(context, "SYS_RAND", JS_Rand);
|
||||
TRI_AddGlobalFunctionVocbase(context, "SYS_READ", JS_Read);
|
||||
TRI_AddGlobalFunctionVocbase(context, "SYS_SAVE", JS_Save);
|
||||
TRI_AddGlobalFunctionVocbase(context, "SYS_SHA256", JS_Sha256);
|
||||
|
|
Loading…
Reference in New Issue