Users & Groups

This commit is contained in:
Correl Roush 2016-04-26 17:21:43 -04:00 committed by Correl Roush
parent 06bd134426
commit e37ac34629
8 changed files with 141 additions and 29 deletions

View file

@ -1,4 +1,6 @@
%% -*- mode: erlang -*-
{["static", '*'], 'elmdap-static', []}.
{["uid", uid], 'elmdap-uid', []}.
{["users", uid], 'elmdap-user', []}.
{["users"], 'elmdap-users', []}.
{["groups"], 'elmdap-groups', []}.

View file

@ -3,11 +3,12 @@
{deps, [
{lfe, {git, "git://github.com/rvirding/lfe", {tag, "1.0"}}},
{calrissian, {git, "git://github.com/correl/calrissian", {branch, "rebar3"}}},
{webmachine, ".*", {git, "git://github.com/basho/webmachine.git", {branch, "master"}}}
]}.
{plugins, [
{'lfe-compile', {git, "https://github.com/lfe-rebar3/compile.git", {tag, "0.3.0"}}}
{'lfe-compile', {git, "https://github.com/lfe-rebar3/compile.git", {tag, "0.4.0"}}}
]}.
{provider_hooks, [
@ -30,8 +31,8 @@
{profiles, [
{dev, [
{plugins, [
{'lfe-version', ".*", {git, "https://github.com/lfe-rebar3/version.git", {tag, "0.3.0"}}},
{'lfe-repl', ".*", {git, "https://github.com/lfe-rebar3/repl.git", {tag, "0.2.0"}}},
{'lfe-version', ".*", {git, "https://github.com/lfe-rebar3/version.git", {tag, "0.4.0"}}},
{'lfe-repl', ".*", {git, "https://github.com/lfe-rebar3/repl.git", {tag, "0.2.1"}}},
{'lfe-clean', ".*", {git, "https://github.com/lfe-rebar3/clean.git", {tag, "0.2.0"}}}
]}
]},

17
src/elmdap-entry.lfe Normal file
View file

@ -0,0 +1,17 @@
(defmodule elmdap-entry
(export all))
(defun dn
((`#(eldap_entry ,dn ,_))
dn))
(defun attributes
((`#(eldap_entry ,_ ,attributes))
attributes))
(defun to_json (entry)
`#(struct [#(dn ,(dn entry))
#(attributes
#(struct ,(lists:map
(match-lambda ((`#(,k ,v)) `#(,k #(array ,v))))
(attributes entry))))]))

45
src/elmdap-groups.lfe Normal file
View file

@ -0,0 +1,45 @@
(defmodule elmdap-groups
(export (init 1)
(service_available 2)
(is_authorized 2)
(content_types_provided 2)
(to_json 2)))
(include-lib "webmachine/include/webmachine.hrl")
(include-lib "calrissian/include/monads.lfe")
(defrecord state
connection)
(defun service_available (req-data state)
(case (elmdap:open)
((tuple 'ok connection)
`#(true ,req-data ,(set-state state connection connection)))
(_
`#(false ,req-data ,state))))
(defun is_authorized (req-data state)
(elmdap:is_authorized (state-connection state)
req-data state))
(defun init (args)
`#(ok ,(make-state)))
(defun content_types_provided (req-data state)
`#([#("application/json" to_json)] ,req-data ,state))
(defun to_json (req-data state)
(tuple (mochijson:encode
`#(array ,(lists:map (fun elmdap-entry to_json 1)
(groups (state-connection state)))))
req-data
state))
(defun groups (connection)
(let* ((base "ou=groups,dc=coredial,dc=com")
(filter (eldap:equalityMatch "objectClass" "groupOfNames"))
(`#(ok #(eldap_search_result ,results ,_))
(eldap:search connection
`[#(base ,base)
#(filter ,filter)])))
results))

View file

@ -1,4 +1,4 @@
(defmodule elmdap-uid
(defmodule elmdap-user
(export (init 1)
(service_available 2)
(resource_exists 2)
@ -22,35 +22,20 @@
(defun resource_exists (req-data state)
(let ((`[#(uid ,uid)] (wrq:path_info req-data)))
(case (elmdap:from-uid uid)
(case (elmdap:from-uid (state-connection state) uid)
(`#(ok ,entry)
`#(true ,req-data ,(set-state state entry entry)))
(_ `#(false ,req-data ,state)))))
(defun is_authorized (req-data state)
(let ((auth-header "Basic realm=Elmdap"))
(case (elmdap:basic-auth-credentials req-data)
(`#(ok ,uid ,password)
(case (elmdap:from-uid uid)
(`#(ok ,entry)
(case (eldap:simple_bind (state-connection state)
(elmdap:entry-dn entry)
password)
('ok `#(true ,req-data ,state))
(_ `#(,auth-header ,req-data ,state))))
(_ `#(,auth-header ,req-data ,state))))
(_ `#(,auth-header ,req-data ,state)))))
(elmdap:is_authorized (state-connection state)
req-data state))
(defun content_types_provided (req-data state)
`#((#("application/json" to_json)) ,req-data ,state))
(defun to_json (req-data state)
(let* ((entry (state-entry state)))
(tuple (mochijson:encode
`#(struct [#(dn ,(elmdap:entry-dn entry))
#(attributes
#(struct ,(lists:map
(match-lambda ((`#(,k ,v)) `#(,k #(array ,v))))
(elmdap:entry-attributes entry))))]))
(tuple (mochijson:encode (elmdap-entry:to_json entry))
req-data
state)))

45
src/elmdap-users.lfe Normal file
View file

@ -0,0 +1,45 @@
(defmodule elmdap-users
(export (init 1)
(service_available 2)
(is_authorized 2)
(content_types_provided 2)
(to_json 2)))
(include-lib "webmachine/include/webmachine.hrl")
(include-lib "calrissian/include/monads.lfe")
(defrecord state
connection)
(defun service_available (req-data state)
(case (elmdap:open)
((tuple 'ok connection)
`#(true ,req-data ,(set-state state connection connection)))
(_
`#(false ,req-data ,state))))
(defun is_authorized (req-data state)
(elmdap:is_authorized (state-connection state)
req-data state))
(defun init (args)
`#(ok ,(make-state)))
(defun content_types_provided (req-data state)
`#([#("application/json" to_json)] ,req-data ,state))
(defun to_json (req-data state)
(tuple (mochijson:encode
`#(array ,(lists:map (fun elmdap-entry to_json 1)
(users (state-connection state)))))
req-data
state))
(defun users (connection)
(let* ((base "ou=people,dc=coredial,dc=com")
(filter (eldap:equalityMatch "objectClass" "inetOrgPerson"))
(`#(ok #(eldap_search_result ,results ,_))
(eldap:search connection
`[#(base ,base)
#(filter ,filter)])))
results))

View file

@ -5,6 +5,7 @@
{applications,
[kernel,
stdlib,
calrissian,
inets,
crypto,
mochiweb,

View file

@ -1,6 +1,8 @@
(defmodule elmdap
(export all))
(include-lib "calrissian/include/monads.lfe")
;; Public API
(defun entry-dn
@ -12,6 +14,11 @@
attributes))
(defun from-uid (uid)
(do-m (monad 'error)
(connection <- (open))
(from-uid connection uid)))
(defun from-uid (connection uid)
(let* ((`#(ok ,connection) (open))
(base "ou=people,dc=coredial,dc=com")
(filter (eldap:equalityMatch "uid" uid))
@ -37,11 +44,20 @@
((binary "Basic " (base64 binary))
(case (string:tokens (base64:mime_decode_to_string base64) ":")
((list uid password)
`#(ok ,uid ,password))
`#(ok #(,uid ,password)))
(_ #(error bad_data))))
(_ #(error bad_method))))))
(defun valid-auth? (connection dn password)
(case (eldap:simple_bind connection dn password)
('ok 'true)
(_ 'false)))
(defun is_authorized (connection req-data state)
(let-function ((fst (match-lambda ((`#(,a ,_)) a)))
(snd (match-lambda ((`#(,_ ,b)) b))))
(let ((result
(do-m (monad 'error)
(credentials <- (elmdap:basic-auth-credentials req-data))
(entry <- (elmdap:from-uid (fst credentials)))
(eldap:simple_bind connection
(elmdap:entry-dn entry)
(snd credentials)))))
(case result
('ok (tuple 'true req-data state))
(_ (tuple "Basic realm=Elmdap" req-data state))))))