imfreedom/ansible

Parents 30a484da0840
Children 844d93849280
Move from using lua to the checkpassword protocol and get everything working
--- a/inventories/pidgin/vault.yaml Mon Nov 22 04:23:25 2021 -0600
+++ b/inventories/pidgin/vault.yaml Tue Nov 23 00:51:00 2021 -0600
@@ -1,81 +1,94 @@
$ANSIBLE_VAULT;1.1;AES256
-36353331646365323738633132363564323161633261323539366335646238313866323033643239
-6132316237633831656330313638346664646136623334640a623035303130636438346331303862
-39326366663663306335313331646131323235633062646235323164643331616466363965326535
-3535356566326531370a303633383730643930313139363766353563653037353137303764376365
-62343035636631323337643631623432313736393563303030353266313630633939393937363362
-64646162383931303636633137316438613435613262336432366163306537353434386166653138
-37343430633863336361663566623038383633333963656230613730646462363638636661663263
-38373532313362366565316439353534373265356334363233653531313134653539363335623637
-39393138376131613035336532626334643966656436316564666631363438613862363330646562
-62643237623839653733346533383531373661373138343334653036366462336663323136646630
-30653433626461343764303263663235336533613039643266653835643331386633653063663866
-30623037343462363836346266663839623336313232333837386230303765313434373162613835
-30356435306434393831396239653033343238396131656131643235303665366364326537623639
-34633137303435313963333734393961313339316338386162303735363834656639653262323761
-63363735613262613765383164626233383137326263316137363735616364383136326235663965
-63623434333835353633343330623262613837373836643339316532393065653731336239636631
-33336437663561626632336137323438373139313661333231323231386161376433353064303933
-34363837613566666330656133353331636639633833303737383461653630396137313731623530
-33316366313433613938643731306330653431616562363134363031316461663265646465613162
-64343831363864373163623634323133303435613136326537636139646364343935363438643835
-30643566363638643361353430626639336531383236373832343364313465353239353966663933
-32323762613233653164666631356433353137383031633961333932633739313763346465323130
-38383765333363626132633763383131313333613935396466326263323864383833366565636539
-64633966343066613930323332373834636335316431363936343932366536353939646437323937
-63653739643834346562393031313037633233633933393036653032643964653134373363376431
-36343462636532306133303763393562366663633263643034313933383765653839316539386664
-32383839386533333339616238306233376335303466373563326264663938653638626365636339
-62346262366630323538623363386434393665383166393862623135663264313330373066373066
-65363839356435346164643266343930303035656363323635373437383566656635653266386539
-66356233326562313531353133346532373538363537316135633432316437383435383365373334
-63346633303765653463633965646261326665303337373361663732333130356530646239386438
-33613162303461313564313361353865353436313936363733373633663238623561306165313135
-61356532303134376534643331643932653431626638613530613735383532343132633330336466
-36633233326439616433386161663962313439353636633765333838633964393538373162333334
-30353664336266363762306236343731353463323265323935376462326665613833663930336630
-36666432663064653330383666313031373633633664383830636137356362326535336633343330
-36636234613966366435626237363036633737653232326263656562323465376361346531313065
-32653735396466396166366234336339313063366334626330333562616630666531333665333835
-62313062336466363765316137326365666466363632613330646137303833653338373134396465
-39383463323036656331363864626430343062666463323933613761616630383331346539366563
-65663237643066643134343730356436646238663065376239333162636431343633373630653033
-39623266313462646361346433623235366336323838336232326363313262386338306439626339
-38633135623364373635666466393466646265626232646433623130313830613537313561386434
-65613631373130663862343034643265633566343162383164633239626432356139623564323330
-38363033663738366136366563313137386338326135376434386563636438353734336663356563
-63356439373730333730376365613431656338663831373362363132613364663135343831306336
-65663663636565326636303033323032663864383037333865633766393837623332303665613635
-34636437653664633964663061623962636162653532643732613134373065633661356632343536
-30303930636536396263656539623739396535303165626162313765393463613838663133363932
-39343638353532626139313833383062623934306138623065323938626634303133383262616435
-39393364656534396536633963633634346661343236346336386439396363643262383737616331
-62323463663830313638373064353131303731656637633431373533613166303062663736376631
-63623164353437316332313735333138623962316363393936366365393661343836346535376461
-65616332393139363361343438623839313235326332626266646237356635643662323238393962
-39343633383939613063633639393964363133643839386639346531326630366135376663646534
-36633761656536363037333335363038336539373135313261313832393662393562386364373430
-38333734343463383566386665333266623037323633323963333962663263626166383664353166
-65393830393038366664383230313435353563623665393938626234316463343432366164356533
-36353562313236336465336134353839636632383030653134643834363433616466373161613463
-61633234653234643333336161616132633265663130386461626666636538636563346466303031
-66663333636235303964663438643537316230663737613264356531386165363733356163333638
-33383762373531396137376530626562353034336331343662393463623865653364333966306131
-65626638333839616235646364353537656363316532366565376265343561356635613136373139
-39313163613032626137613830646161326662616336313436393731353934663733636330316531
-66386632386362643737383866373634656231313437616530353432306336363231326161623962
-65363530373162613864333934336161643163633933646434646338393062386464313139343839
-35343631663030666361656565353063363965643237383566306566396338353961323266306264
-64356365613331653837313337663535626535323563626266616466303139353938396439616466
-64326130393936356231343632333364613962626666636337646364303231613931393834303761
-63326361656538303262306566656136356466376535346337336536623836646161393963346335
-31666439313939626131383538363766306238306266353733313263306536333339303932663132
-36386364653961346165656161623030663261316534393031326666633766633462623933363362
-62396132346236623066353038303965616462363432376633363663386330626636363562643338
-35373131333666633764303039373438316265386230303330613234393766383961613232316634
-63306361626166616561333730636265363737653539343538316636333633323564353932383736
-65656633616234656666393861343866616434646630313264356331636263346133666539373662
-63306339656564616365663764613339386464343135386264396465633237653761383133386232
-32356231353336623834343961373333306162303138326631653631343431383438323065333632
-38656261376133643130356666633065616161663334363562633739346363313630313832313032
-37396632336439626633
+37343535666563666230616263643636383965616564353266336237313439356461373036363065
+3630636436363136613231353834313435343730313334330a316138323331653735313430623830
+64303638626436323432613930643164336631323532306639326535326537383330386266353864
+3362613836333134330a393739656132636238613163323733383330623538363664323864623462
+34633763333638363462356662633062346466303138653230636236613466636566386637356539
+64653638633339396630373734386661636536353139383537663865663533666533313566346635
+38633366343533333530313964363431366161643061393764633963656433666531656164363633
+32396563663563323635306339666364633363306661666165383432623761653234376231303466
+30393534643836303536363336653462366232386630343037646236323661633863333065656235
+31306238663665393265633932343933633361356465326537646137323033343966636538393131
+34373963353231376439356261633264613461363866363162373138353930366665656661326637
+38303034616439623662386662373138353465373936666561373261306266323266323165613136
+35346363613437633963323061653338626134383734303833316464623437373435343438346331
+63396661396233333230323731633235306163623462303362303161636461616631363937306638
+61313962313162383138646264643036633037663265383161663530666336363235643239653362
+61393036323530616664643434663537663463353862353132626233343137653161383866613531
+61646238376438393261356233303637663533643036323161363764343561303532386135313163
+61373839633863333234356163343538356163313239646361663463323837353132323835663135
+64383936303266633932666361336338323666333563656230643332323131353532366238666232
+39316230616431343239373361613131366565646262653338333733393362386530346164353831
+64336365663564633232363366383130313136663335373139613930306231366137333664336565
+65333164633461353762346137366636393338356635343436313065373033623566343131623439
+32656463633936653239393038343630336261356638356136303734623361633161643565636335
+30636433303462373939613136326531653861326137653164303931353633623730636266633932
+61306561643330373265666537623737633730343832633934336561393937646232646130383632
+35326532613263343333333431613666626163633564306461383234303264653861613139333866
+33343535303966623236643266613165373763653866363130666165656434626666623964366533
+66343738313530663961316439326539333132303936323736636366613233393430653335636366
+31353565373065636433363436346238646364373532623137363635343639613935656434653238
+66663563623230333064386531626530356338636533386336366365653565363762646265306435
+66646539306236633538633734666238363563386532623131373135613364656365616431323537
+30386664643566386265356139396634316666656635306132636633373530386362333839313662
+61633532373438616136653566626434653338396362656231326163316235363933343630363537
+64303335386536643732366165656134336561393738636633386361386132363834326466306536
+39356534616330386431643635616163343862343464653063663834303963356165343333393164
+64386439356633313437323564316365613036343434396633343235623036313064376164316264
+34353834383330646537663061336665626231336161613036633065383030623830613730316564
+34386136383932646238343437323633313564636366623933343864663066336535656139383939
+30636437386437326637346162646238336262653239636464636335306362623039313365393936
+65656562303539373532346133303233393561646163303165633966623162373032313762336137
+37353435303362326532313036386336616561333435376333323361306339373230346339643630
+36316533313166653432303564316534303731396530363662653961666566333562363365626237
+38616465396538306366336334383562353261316131386465643732396464623134356236333965
+38353061623835316337653933313263326235383339636237613030383731353635383139383362
+39323032633432643266636139313633633031333735643736393135616631386135616132376234
+32613961363366363331613964643665303539623737326232353863353138316232303736366535
+36373632363931386566393661323836373961376361623930373535326339373765653332653261
+30303264663332656338303637353063313733616530613631636562383439633064656438336566
+38633839393531633638653636306331643435326363626165303566386362636661333834323437
+37666632393830643339386264333731366338666536616537373435643861653166323931313432
+66643466313230656561663130343131343230396466666564656633633663313331373662653239
+64656236653261383764386332333762333232326166656439343131373835373464616331343633
+36363731316638353163643530373432643037376462373033343534363137326332616464636562
+35316234343166353633383766383631303435396462373039343132396638353035653631326436
+61663461333331643364396261356563313964366333633331663464333066323532626636333336
+62323962383031326165663435363331663930633838353031313032383561336263346632396165
+62643666613432633164653131316264633064363835363136653563616263346132313637336366
+39663961623764393133396632313064366363646234646130333335333439653536653332633038
+34613039363366363965323866623764633063316338646462646231326131303932663265353333
+35356134653039356563613865313835346237303131343537396166313265393038386339366631
+36366132383930366463656136313534336562636336666338616539346337303639366532643933
+36646136346630303438306137643038323265646363626262363633373565393338636239353737
+34323038393166306535353865326631643563303664303735666632316431643664383430363264
+31393330376331393566333063613165613862343130373364616532396562366666653738666666
+38383839366438643935353831653061356365393464376566663632623363616438346438643437
+31343035663166353263326466346138666235333738353031333130306666663832383464343861
+36316130356336313431333437613863326334323931643131623739343961643934303932643765
+61376562626538666265333164373065336132626636613734306134366665366530623364616132
+65383262663932303433616632393430306464363733333233333531666664393964313363376365
+32633735666533316335376363386531363263313930643733633533333933613937373230613764
+66333264666230313261363330323533653638616363343638316537623436613339396332326363
+62386534616136616434643963396463393338643562316532316461643063663366353734643639
+61663438643861333062343861653663353861336437353934376132633039313833306636636662
+37383531316363373539356532333335663036613161616164613866353630656636613065326134
+35663666636166646461353362613738656264656436386139376333343333396562383964313533
+32663365326235656636636265643063363332633062646366356465303739663865623936643466
+62373462353862303132636365373238353636666130646535636133666465383435613264333537
+63313433303935666532353666623339353637306135336666363833303864333139623536323830
+64636162303735633837396532333533346536383165666438376264373738313534613637363861
+63373636316533336262643535643162393038613961303039383837623637343161626330306438
+65333935623530353263316532303963323566333765313038363334343262326639396165353631
+37383762363932656239313965636139303631363730313533373538393233353962626339373636
+39373030373136353531313633616563353631353931396365376535376566636634633339363132
+66353732666337306434346366333830383633386561343337626334326463386462643266313638
+30383436323830393734626162646139323162373362326636353536353139353139303136333962
+35313166663639636639323737613764343831653236623134616431663330613539326562356564
+31323562316437316537383762643539353364396234323064623431393938616663633731383361
+62623931353039643937626465323237343438363832623538646664316632363638653831373133
+35383632623530323863356332303132373061653964333238653461663162373966633036336432
+31313738623638356533396636386431356431316262316531303337333365363538633731643563
+39333262386334366262663964316139613164633937666265346266346263613431363935383030
+33396665616333653866626638383139373232626334623433333664643532366338303632636362
+62623830336562396566323639346162623065363634373261313565333363643438
--- a/mail_servers.yaml Mon Nov 22 04:23:25 2021 -0600
+++ b/mail_servers.yaml Tue Nov 23 00:51:00 2021 -0600
@@ -1,5 +1,5 @@
---
- hosts: mail_servers
roles:
- - update
+ # - update
- mail
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/roles/mail/files/dovecot-10-auth-checkpassword.conf Tue Nov 23 00:51:00 2021 -0600
@@ -0,0 +1,10 @@
+passdb {
+ driver = checkpassword
+ args = /usr/local/bin/dovecot-auth-imf-hub.py
+}
+
+userdb {
+ driver = static
+ args = uid=vmail gid=vmail
+}
+
--- a/roles/mail/files/dovecot-10-auth-lua.conf Mon Nov 22 04:23:25 2021 -0600
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,10 +0,0 @@
-passdb {
- driver = lua
- args = file=/etc/dovecot/auth-imf-hub.lua blocking=yes
-}
-
-userdb {
- driver = lua
- args = file=/etc/dovecot/auth-imf-hub.lua blocking=yes
-}
-
--- a/roles/mail/tasks/dovecot.yaml Mon Nov 22 04:23:25 2021 -0600
+++ b/roles/mail/tasks/dovecot.yaml Tue Nov 23 00:51:00 2021 -0600
@@ -45,11 +45,18 @@
when: "false and packaged_10_auth_conf.stat.exists"
notify:
- "reload dovecot"
-- name: "add lua based auth configuration"
- file:
- copy:
- src: "dovecot-10-auth-lua.conf"
- dest: "/etc/dovecot/conf.d/10-auth-lua.conf"
- mode: "0644"
+- name: "add checkpassword based auth configuration"
+ copy:
+ src: "dovecot-10-auth-checkpassword.conf"
+ dest: "/etc/dovecot/conf.d/10-auth-checkpassword.conf"
+ mode: "0644"
notify:
- "reload dovecot"
+- name: "add python checkpassword script"
+ template:
+ src: "dovecot-auth-imf-hub.py.j2"
+ dest: "/usr/local/bin/dovecot-auth-imf-hub.py"
+ mode: "0500"
+ owner: "dovecot"
+ notify:
+ - "reload dovecot"
--- a/roles/mail/tasks/software.yaml Mon Nov 22 04:23:25 2021 -0600
+++ b/roles/mail/tasks/software.yaml Tue Nov 23 00:51:00 2021 -0600
@@ -11,6 +11,9 @@
- "dovecot-core"
- "dovecot-imapd"
- "dovecot-lmtpd"
+ - "lua-dkjson"
+ - "lua-lpeg"
+ - "lua-sec"
- "lua-socket"
tags:
- "dovecot"
--- a/roles/mail/templates/auth-imf-hub.lua.j2 Mon Nov 22 04:23:25 2021 -0600
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,121 +0,0 @@
--- vi:ft=lua
--- This is a templated file created by ansible and any changes made to it will
--- be over written during the next run. So do NOT edit this file, please go
--- through the ansible workflow to keep everyone happy.
-
-local string = require("string")
-
-local mime = require("mime")
-
-local hub_url = "{{ mail_hub_url }}"
-local hub_scopes = "{{ mail_hub_scopes }}"
-local hub_client_id = "{{ mail_hub_client_id }}"
-local hub_client_secret = "{{ mail_hub_client_secret }}"
-
-local hub_domain_groups = {
- "pidgin.im" = { "Pidgin Developer", "Pidgin Contributor", "Pidgin Email" };
- "imfreedom.org" = {"IMF Board"};
-}
-
--- The following code is borrowed from prosody's util.http.
-local url_codes = {};
-for i = 0, 255 do
- local c = char(i);
- local u = format("%%%02x", i);
- url_codes[c] = u;
- url_codes[u] = c;
- url_codes[u:upper()] = c;
-end
-
-local function urlencode(s)
- return s and (s:gsub("[^a-zA-Z0-9.~_-]", url_codes));
-end
-
-local function _formencodepart(s)
- return s and (urlencode(s):gsub("%%20", "+"));
-end
-
-local function formencode(form)
- local result = {};
- if form[1] then -- Array of ordered { name, value }
- for _, field in ipairs(form) do
- table.insert(result, _formencodepart(field.name).."=".._formencodepart(field.value));
- end
- else -- Unordered map of name -> value
- for name, value in pairs(form) do
- table.insert(result, _formencodepart(name).."=".._formencodepart(value));
- end
- end
- return table.concat(result, "&");
-end
-
-function http_request(url, headers, body)
- local ltn12 = require("ltn12")
-
- local request;
-
- if string.sub(url, 1, string.len("https")) == "https" then
- request = require("ssl.https").request
- else
- request = require("socket.http").request
- end
-
- local t = {}
-
- _, code, _ = request{
- url = url,
- headers = headers,
- sink = ltn12.sink.table(t),
- }
-
- if body and #body > 0 then
- request["body"] = formencode(body)
- end
-
- return {
- code = code,
- content = table.concat(t)
- }
-end
--- end of prosody util.http
-
--- verify the users password
-function auth_password_verify(request, password)
- if request.domain == "" then
- return dovecot.auth.USERDB_RESULT_USER_UNKNOWN, "no domain specified"
- end
-
- if hub_domain_groups[request.domain] == nil then
- return dovecot.auth.USERDB_RESULT_USER_UNKNOWN, "unknown domain"
- end
-
- request.log_info("testing password for " . request.user)
-
- local token = mime.b64(string.format("%s:%s", hub_client_id, hub_client_secret))
- local headers = {
- Authorization = string.format("Basic %s", token);
- };
- local body = {
- "grant_type" = "password";
- "username" = request.username;
- "password" = password;
- "scope" = hub_scopes;
- };
-
- local resp = http_request(hub_url.."/api/rest/oauth2/token", headers, body);
-
-end
-
--- verify the user exists
-function auth_userdb_lookup(request)
-end
-
--- script lifecycle
-function script_init()
- return 0
-end
-
-function script_deinit()
-end
-
-
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/roles/mail/templates/dovecot-auth-imf-hub.py.j2 Tue Nov 23 00:51:00 2021 -0600
@@ -0,0 +1,166 @@
+#!/usr/bin/env python3
+
+# This script implements the dovecot checkpassword interface and ties it into
+# jetbrains hub.
+#
+# See https://wiki2.dovecot.org/AuthDatabase/CheckPassword for more infromation
+# on the interface.
+
+import base64
+import json
+import os
+import sys
+import urllib.request
+import urllib.parse
+
+
+hub_url = "{{ mail_hub_url }}"
+hub_scopes = "{{ mail_hub_scopes }}"
+hub_client_id = "{{ mail_hub_client_id }}"
+hub_client_secret = "{{ mail_hub_client_secret }}"
+hub_permanent_token = "{{ mail_hub_permanent_token }}"
+
+hub_domain_groups = {
+ "pidgin.im": ["Pidgin Developer", "Pidgin Contributor", "Pidgin Email"],
+ "imfreedom.org": ["IMF Board"],
+}
+
+vmail_uid = "998"
+vmail_gid = "998"
+
+vmail_path_format = "/srv/mail/{domain}/{user}"
+
+http_timeout = 30
+
+def request_group_query(domain):
+ groups = hub_domain_groups[domain]
+
+ # use json.dumps to force quote the string
+ parts = [f"in:{json.dumps(x)}" for x in groups]
+
+ return " or ".join(parts)
+
+
+def check_group(user, domain):
+ headers = {
+ "Authorization": f"Bearer {hub_permanent_token}",
+ }
+
+ try:
+ query = request_group_query(domain)
+ except KeyError:
+ print(f"unknown domain {domain}")
+ return False
+
+ params = {
+ "$top": "1",
+ "query": f"login:{user} and ({query})",
+ "fields": "login",
+ }
+
+ url = f"{hub_url}/api/rest/users?"
+ url += urllib.parse.urlencode(params)
+
+ req = urllib.request.Request(url, headers=headers)
+ with urllib.request.urlopen(req, timeout=http_timeout) as resp:
+ code = resp.getcode()
+ if code < 200 or code > 299:
+ print(f"invalid response {code}")
+ return False
+
+ data = json.loads(resp.read())
+
+ if "users" in data and len(data["users"]) == 1:
+ if "login" in data["users"][0] and data["users"][0]["login"] == user:
+ return True
+
+ return False
+
+
+def validate_credentials(user, domain, password):
+ token = base64.b64encode(f"{hub_client_id}:{hub_client_secret}".encode("utf-8"))
+ strToken = token.decode("utf-8")
+ headers = {
+ "Authorization": f"Basic {strToken}"
+ }
+
+ body = {
+ "grant_type": "password",
+ "username": user,
+ "password": password,
+ "scope": hub_scopes,
+ }
+ data = urllib.parse.urlencode(body).encode("ascii")
+
+ url = f"{hub_url}/api/rest/oauth2/token"
+ req = urllib.request.Request(url, data=data, headers=headers)
+
+ with urllib.request.urlopen(req, timeout=http_timeout) as resp:
+ status = resp.getcode()
+ if status < 200 or status > 299:
+ return False
+
+ # if we got 2xx response, check if the user is in a group that can
+ # access email.
+ return check_group(user, domain)
+
+ return False
+
+
+def check_password():
+ pass
+
+def main():
+ data = os.read(3, 512)
+ try:
+ username, password, _ = data.split(b"\x00", 2)
+ except ValueError:
+ print("invalid input")
+
+ sys.exit(1)
+
+ username = username.decode("utf-8")
+ password = password.decode("utf-8")
+
+ try:
+ user, domain = username.split("@", 1)
+ except ValueError:
+ print("no domain specified")
+
+ sys.exit(1)
+
+ try:
+ authorized = os.environ.get("AUTHORIZED", "0")
+
+ if authorized == "1":
+ # userdb lookups
+ if not check_group(user, domain):
+ sys.exit(3)
+ else:
+ # passdb lookups
+ if not validate_credentials(user, domain, password):
+ print("invalid credentials")
+
+ sys.exit(1)
+
+ if len(sys.argv) > 1:
+ os.environ.update({
+ "userdb_uid": vmail_uid,
+ "userdb_gid": vmail_gid,
+ "INSECURE_SETUID": "1",
+ "HOME": vmail_path_format.format(user=user, domain=domain),
+ "EXTRA": "userdb_uid userdb_gid"
+ })
+
+ os.execvp(sys.argv[1], sys.argv[1:])
+
+ except Exception as e: # assume any exceptions are temporary failures
+ print(f"Caught exception {e}")
+ raise e
+
+ # if we hit an http error, return 111 to note a temporary failure.
+ sys.exit(111)
+
+
+if __name__ == "__main__":
+ main()