74bc22ae50
Reviewed-on: https://akkoma.dev/AkkomaGang/akkoma/pulls/40 Co-authored-by: norm <normandy@biribiri.dev> Co-committed-by: norm <normandy@biribiri.dev>
136 lines
3.9 KiB
Markdown
136 lines
3.9 KiB
Markdown
# Configuring Ejabberd (XMPP Server) to use Akkoma for authentication
|
|
|
|
If you want to give your Akkoma users an XMPP (chat) account, you can configure [Ejabberd](https://github.com/processone/ejabberd) to use your Akkoma server for user authentication, automatically giving every local user an XMPP account.
|
|
|
|
In general, you just have to follow the configuration described at [https://docs.ejabberd.im/admin/configuration/authentication/#external-script](https://docs.ejabberd.im/admin/configuration/authentication/#external-script). Please read this section carefully.
|
|
|
|
Copy the script below to suitable path on your system and set owner and permissions. Also do not forget adjusting `AKKOMA_HOST` and `AKKOMA_PORT`, if necessary.
|
|
|
|
```bash
|
|
cp akkoma_ejabberd_auth.py /etc/ejabberd/akkoma_ejabberd_auth.py
|
|
chown ejabberd /etc/ejabberd/akkoma_ejabberd_auth.py
|
|
chmod 700 /etc/ejabberd/akkoma_ejabberd_auth.py
|
|
```
|
|
|
|
Set external auth params in ejabberd.yaml file:
|
|
|
|
```bash
|
|
auth_method: [external]
|
|
extauth_program: "python3 /etc/ejabberd/akkoma_ejabberd_auth.py"
|
|
extauth_instances: 3
|
|
auth_use_cache: false
|
|
```
|
|
|
|
Restart / reload your ejabberd service.
|
|
|
|
After restarting your Ejabberd server, your users should now be able to connect with their Akkoma credentials.
|
|
|
|
|
|
```python
|
|
import sys
|
|
import struct
|
|
import http.client
|
|
from base64 import b64encode
|
|
import logging
|
|
|
|
|
|
AKKOMA_HOST = "127.0.0.1"
|
|
AKKOMA_PORT = "4000"
|
|
AUTH_ENDPOINT = "/api/v1/accounts/verify_credentials"
|
|
USER_ENDPOINT = "/api/v1/accounts"
|
|
LOGFILE = "/var/log/ejabberd/akkoma_auth.log"
|
|
|
|
logging.basicConfig(filename=LOGFILE, level=logging.INFO)
|
|
|
|
|
|
# Akkoma functions
|
|
def create_connection():
|
|
return http.client.HTTPConnection(AKKOMA_HOST, AKKOMA_PORT)
|
|
|
|
|
|
def verify_credentials(user: str, password: str) -> bool:
|
|
user_pass_b64 = b64encode("{}:{}".format(
|
|
user, password).encode('utf-8')).decode("ascii")
|
|
params = {}
|
|
headers = {
|
|
"Authorization": "Basic {}".format(user_pass_b64)
|
|
}
|
|
|
|
try:
|
|
conn = create_connection()
|
|
conn.request("GET", AUTH_ENDPOINT, params, headers)
|
|
|
|
response = conn.getresponse()
|
|
if response.status == 200:
|
|
return True
|
|
|
|
return False
|
|
except Exception as e:
|
|
logging.info("Can not connect: %s", str(e))
|
|
return False
|
|
|
|
|
|
def does_user_exist(user: str) -> bool:
|
|
conn = create_connection()
|
|
conn.request("GET", "{}/{}".format(USER_ENDPOINT, user))
|
|
|
|
response = conn.getresponse()
|
|
if response.status == 200:
|
|
return True
|
|
|
|
return False
|
|
|
|
|
|
def auth(username: str, server: str, password: str) -> bool:
|
|
return verify_credentials(username, password)
|
|
|
|
|
|
def isuser(username, server):
|
|
return does_user_exist(username)
|
|
|
|
|
|
def read():
|
|
(pkt_size,) = struct.unpack('>H', bytes(sys.stdin.read(2), encoding='utf8'))
|
|
pkt = sys.stdin.read(pkt_size)
|
|
cmd = pkt.split(':')[0]
|
|
if cmd == 'auth':
|
|
username, server, password = pkt.split(':', 3)[1:]
|
|
write(auth(username, server, password))
|
|
elif cmd == 'isuser':
|
|
username, server = pkt.split(':', 2)[1:]
|
|
write(isuser(username, server))
|
|
elif cmd == 'setpass':
|
|
# u, s, p = pkt.split(':', 3)[1:]
|
|
write(False)
|
|
elif cmd == 'tryregister':
|
|
# u, s, p = pkt.split(':', 3)[1:]
|
|
write(False)
|
|
elif cmd == 'removeuser':
|
|
# u, s = pkt.split(':', 2)[1:]
|
|
write(False)
|
|
elif cmd == 'removeuser3':
|
|
# u, s, p = pkt.split(':', 3)[1:]
|
|
write(False)
|
|
else:
|
|
write(False)
|
|
|
|
|
|
def write(result):
|
|
if result:
|
|
sys.stdout.write('\x00\x02\x00\x01')
|
|
else:
|
|
sys.stdout.write('\x00\x02\x00\x00')
|
|
sys.stdout.flush()
|
|
|
|
|
|
if __name__ == "__main__":
|
|
logging.info("Starting akkoma ejabberd auth daemon...")
|
|
while True:
|
|
try:
|
|
read()
|
|
except Exception as e:
|
|
logging.info(
|
|
"Error while processing data from ejabberd %s", str(e))
|
|
pass
|
|
|
|
```
|