Welcome to mirror list, hosted at ThFree Co, Russian Federation.

mumble-auth.py « scripts - github.com/mumble-voip/mumble.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: 1a28328fa8ef45bd9b985580030c7801153d87e9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
#!/usr/bin/env python
# -*- coding: utf-8
#
#    mumble-auth.py - Sample script to show the basics of using server controlled
#                     context menu entries for in-client registration tickets.
#
#    Requirements:
#        * python 2.5 or higher
#        * cherrypy 3 or higher
#        * python ice bindings
#        * murmur + mumble rev 1530 or higher

import cherrypy
import Ice
from threading import Semaphore
import random, time

#
#--- Config stuff
#
baseurl = "http://localhost:8080/register?id=" # Baseurl for registrations
storage_time = 10*24*60*60 # Time in seconds a reg entry is guaranteed to be valid
proxy = "Meta:tcp -h 127.0.0.1 -p 6502"
group = "admin" # ACL group which has the right to send regurls
host = "0.0.0.0" # Interface to listen on
port = 8080 # Cherrypy port
slice = "Murmur.ice"
production = False # Set this to true to surpress tracebacks

# Runtime generate bindings
Ice.loadSlice(slice)
import Murmur

# Global vars
sema_ids = Semaphore()
ids = {}  #Contains list(sid, user, time)


class MetaCallbackI(Murmur.MetaCallback):
    def started(self, s, current=None):
        serverR = Murmur.ServerCallbackPrx.uncheckedCast(adapter.addWithUUID(ServerCallbackI(server, current.adapter)))
        s.addCallback(serverR)
    def stopped(self, s, current=None): pass # Unused callback

class ServerCallbackI(Murmur.ServerCallback):
    def __init__(self, server, adapter):
        self.server = server
        self.contextR=Murmur.ServerContextCallbackPrx.uncheckedCast(adapter.addWithUUID(ServerContextCallbackI(server)))

    def userConnected(self, p, current=None):
        if p.userid != 0: # SuperUser is always allowed
            # Check if the user is in the right acl class and add the context menu
            allowed = False
            for acl in self.server.getACL(0)[1]:
                if acl.name == group and p.userid in acl.members:
                    allowed = True
                    break
            if not allowed:
                return

        self.server.addContextCallback(p.session,
                                       "sendregurl",
                                       "Send registration URL",
                                       self.contextR, Murmur.ContextUser)

    def userDisconnected(self, p, current=None): pass # Unused callbacks
    def userStateChanged(self, p, current=None): pass
    def channelCreated(self, c, current=None): pass
    def channelRemoved(self, c, current=None): pass
    def channelStateChanged(self, c, current=None): pass

class ServerContextCallbackI(Murmur.ServerContextCallback):
    #--- Server message template strings
    err_notallowed = "You are not allowed to send registration urls"
    msg_regurl = "You've been allowed to register with this mumble server, " \
                 "please <a href='%(url)s'>click here to register</a>."


    def __init__(self, server):
      self.server = server

    def contextAction(self, action, p, session, chanid, current=None):
        if action == "sendregurl" and p:
            if p.userid != 0:
                # If it isn't SuperUser check if he is in the right acl group
                allowed = False
                for acl in self.server.getACL(0)[1]:
                    if acl.name == group and p.userid in acl.members:
                        allowed = True
                        break
                if not allowed:
                    self.server.sendMessage(p, self.err_notallowed)
                    return

            sema_ids.acquire()
            try:
                # Take the chance to cleanup old entries
                todel = []
                for key, reg in ids.iteritems():
                    if int(time.time()) - reg[2] > storage_time:
                        todel.append(key)
                for key in todel:
                    del ids[key]

                # Ok, now generate his registration id (64bit)
                rid = None
                while not rid or rid in ids:
                    rid = random.randrange(0, pow(2,64))
                sid = self.server.id()

                # Remember his username
                try:
                    username = self.server.getState(session).name
                except Murmur.InvalidSessionException:
                    username = ""

                # Save everything
                ids[str(rid)] = (sid, username, int(time.time()))
                # Send reg url to the user
                url = baseurl + str(rid)
                self.server.sendMessage(session,
                                        self.msg_regurl % {'url':url})
            finally:
                sema_ids.release()



class mumble_auth(object):
    #--- Web template strings
    template = """<?xml version="1.0" encoding="utf-8" ?>
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
        <head>
            <title>%(title)s</title>
            <style type="text/css">
            label { display:block; font-size:smaller; }
            fieldset { border:1px solid; width:250px; }
            h1 { border-bottom:2px solid; }
            h2 { border-bottom:2px solid red; color:red; }
            </style>
        </head>
        <body>
        <h1>%(title)s</h1>
        %(body)s
        </body>
    </html>"""

    err_id = """<h2>Invalid ID</h2><p>
    The ID for your registration has already been used or is invalid.<br />
    Please request a new registration link from a Mumble administrator.<br /></p>"""

    err_username = """<h2>Invalid username</h2><p>
    The username you chose contains characters which are not allowed.<br/>
    Please only use normal characters without whitespaces.<br /></p>"""

    err_username_existing = """<h2>Username already registered</h2><p>
    The username you chose is already registered on this server.<br />
    Please choose another one.<br /></p>"""

    err_password = """<h2>Invalid password</h2><p>
    The password you chose didn't match the criteria enforced by this server.<br/>
    Your password should be at least 6 characters long.<br /></p>"""

    err_password_mismatch = """<h2>Passwords do not match</h2><p>
    The password you entered did not match the one in the confirmation box.<br/>
    Make sure both boxes contain the same password.<br /></p>"""

    snippet_retry = '<br/><a href="%(url)s">Click here to try again</a>'

    body_index = """<p>This is the mumble-auth script, to be able to register yourself
    an account please ask a admin on the mumble server.</p>"""

    body_complete = """<h2>Success</h2><p>
    You have been registered with the server successfully,<br />
    please try to login to the server with your new login credentials!</p>"""

    body_regform = """
    <form action="doregister" method="post">
        <fieldset>
            <legend>Enter user information</legend>
            <label for="username">Username</label>
            <input id="username" type="text" name="username" value="%(username)s"
                size="20" maxlength="40" /><br />
            <label for="password">Password</label>
            <input id="password" type="password" name="password" value=""
                size="20" maxlength="40" /><br />
            <label for="cpassword">Confirm password</label>
            <input id="cpassword" type="password" name="cpassword" value=""
                size="20" maxlength="40" /><br />
            <input type="hidden" name="id" value="%(id)s" />
            <input id="register" type="submit" value="Register" />
        </fieldset>
    </form>"""

    def __init__(self, murmur):
        self.murmur = murmur

    def index(self):
        title = "Mumble Auth - Index"
        return self.template % {'title':title,
                                'body':self.body_index}
    index.exposed = True

    def register(self, id = None):
        title = "Mumble Auth - Register";
        if not id in ids:
            body = self.err_id # Invalid ID
        else:
            # In case of a valid ID
            body = self.body_regform % {'username':ids[id][1],
                                        'id':id}

        return self.template % {'title':title,
                                'body':body}
    register.exposed = True

    def doregister(self, id = None, username = None, password = None, cpassword = None):
        title = "Mumble Auth - Register";
        sema_ids.acquire()
        try:
            # Check if all parameters are ok
            if not id in ids:
                body = self.err_id # Invalid id
            elif not username or " " in username: # Invalid username
                body = self.err_username + \
                        self.snippet_retry % {'url':baseurl+id}
            elif len(password) < 6:  # Password criteria didn't match
                body = self.err_password + \
                        self.snippet_retry % {'url':baseurl+id}
            elif password != cpassword: # Password mismatch
                body = self.err_password_mismatch + \
                        self.snippet_retry % {'url':baseurl+id}
            else:
                # Ok, try to register him
                server = self.murmur.getServer(ids[id][0])
                if (len(server.getRegisteredUsers(username))!=0):
                    body = self.err_username_existing + \
                            self.snippet_retry % {'url':baseurl+id}
                else:
                    # Register user
                    info = {Murmur.UserInfo.UserName:username,
                            Murmur.UserInfo.UserPassword:password}
                    server.registerUser(info)
                    # Void registration id
                    del ids[id]
                    # Success
                    body = self.body_complete
        finally:
            sema_ids.release()
        return self.template % {'title':title,
                                'body':body}
    doregister.exposed = True

if __name__ == "__main__":
    random.seed()
    ice = Ice.initialize()
    try:
        meta = Murmur.MetaPrx.checkedCast(ice.stringToProxy(proxy))
        adapter = ice.createObjectAdapterWithEndpoints("Callback.Client", "tcp -h 127.0.0.1")
        metaR=Murmur.MetaCallbackPrx.uncheckedCast(adapter.addWithUUID(MetaCallbackI()))
        adapter.activate()

        meta.addCallback(metaR)
        for server in meta.getBootedServers():
            serverR=Murmur.ServerCallbackPrx.uncheckedCast(adapter.addWithUUID(ServerCallbackI(server, adapter)))
            server.addCallback(serverR)

        if production: cherrypy.config.update({'environment': 'production'})
        cherrypy.server.socket_host = host
        cherrypy.server.socket_port = port
        cherrypy.quickstart(mumble_auth(meta))
    finally:
        ice.shutdown()
        ice.waitForShutdown()