|
1 | | -# glauth-postgres |
| 1 | +# GLAuth Plugin |
| 2 | + |
| 3 | +This is a GLAuth plugin; that is, a backend that are not compiled in GLAuth by default. |
| 4 | + |
| 5 | +To quote 'Butonic' (Jörn Friedrich Dreyer): |
| 6 | + |
| 7 | +> Just keep the 'lightweight' in mind. |
| 8 | +
|
| 9 | +To build either back-end, type |
| 10 | +``` |
| 11 | +make plugin_name |
| 12 | +``` |
| 13 | +where 'name' is the plugin's name; so, for instance: `make plugin_sqlite` |
| 14 | + |
| 15 | +To build back-ends for specific architectures, specify `PLUGIN_OS` and `PLUGIN_ARCH` -- |
| 16 | + For instance, to build the sqlite plugin for the new Mac M1s: |
| 17 | + ``` |
| 18 | +make plugin_sqlite PLUGIN_OS=darwin PLUGIN_ARCH=arm64 |
| 19 | + ``` |
| 20 | + |
| 21 | +## Database Plugins |
| 22 | + |
| 23 | +To use a database plugin, edit the configuration file (see pkg/plugins/sample-database.cfg) so that: |
| 24 | + |
| 25 | +``` |
| 26 | +... |
| 27 | +[backend] |
| 28 | + datastore = "plugin" |
| 29 | + plugin = "dynamic library you created using the previous 'make' command" |
| 30 | + database = "database connection string" |
| 31 | +... |
| 32 | +``` |
| 33 | +so, let's say you built the 'sqlite' plugin, you would now specify its library: `database = sqlite.so` |
| 34 | + |
| 35 | +### SQLite, MySQL, Postgres |
| 36 | + |
| 37 | +Tables: |
| 38 | +- users, groups are self-explanatory |
| 39 | +- includegroups store the 'includegroups' relationships |
| 40 | +- othergroups, on the other hand, are a comma-separated list found in the users table (performance) |
| 41 | + |
| 42 | +Here is how to insert example data using your database's REPL (more detailed information can be found in pkg/plugins/sample-database.cfg) |
| 43 | + |
| 44 | +```sql |
| 45 | +INSERT INTO groups(name, gidnumber) VALUES('superheros', 5501); |
| 46 | +INSERT INTO groups(name, gidnumber) VALUES('svcaccts', 5502); |
| 47 | +INSERT INTO groups(name, gidnumber) VALUES('civilians', 5503); |
| 48 | +INSERT INTO groups(name, gidnumber) VALUES('caped', 5504); |
| 49 | +INSERT INTO groups(name, gidnumber) VALUES('lovesailing', 5505); |
| 50 | +INSERT INTO groups(name, gidnumber) VALUES('smoker', 5506); |
| 51 | +INSERT INTO includegroups(parentgroupid, includegroupid) VALUES(5503, 5501); |
| 52 | +INSERT INTO includegroups(parentgroupid, includegroupid) VALUES(5504, 5502); |
| 53 | +INSERT INTO includegroups(parentgroupid, includegroupid) VALUES(5504, 5501); |
| 54 | +INSERT INTO users(name, uidnumber, primarygroup, passsha256) VALUES('hackers', 5001, 5501, '6478579e37aff45f013e14eeb30b3cc56c72ccdc310123bcdf53e0333e3f416a'); |
| 55 | +INSERT INTO users(name, uidnumber, primarygroup, passsha256) VALUES('johndoe', 5002, 5502, '6478579e37aff45f013e14eeb30b3cc56c72ccdc310123bcdf53e0333e3f416a'); |
| 56 | +INSERT INTO users(name, mail, uidnumber, primarygroup, passsha256) VALUES('serviceuser', "serviceuser@example.com", 5003, 5502, '652c7dc687d98c9889304ed2e408c74b611e86a40caa51c4b43f1dd5913c5cd0'); |
| 57 | +INSERT INTO users(name, uidnumber, primarygroup, passsha256, othergroups, custattr) VALUES('user4', 5004, 5504, '652c7dc687d98c9889304ed2e408c74b611e86a40caa51c4b43f1dd5913c5cd0', '5505,5506', '{"employeetype":["Intern","Temp"],"employeenumber":[12345,54321]}'); |
| 58 | +INSERT INTO capabilities(userid, action, object) VALUES(5001, "search", "ou=superheros,dc=glauth,dc=com"); |
| 59 | +INSERT INTO capabilities(userid, action, object) VALUES(5003, "search", "*"); |
| 60 | +``` |
| 61 | +This should be equivalent to this configuration: |
| 62 | +```text |
| 63 | +[[users]] |
| 64 | + name = "hackers" |
| 65 | + uidnumber = 5001 |
| 66 | + primarygroup = 5501 |
| 67 | + passsha256 = "6478579e37aff45f013e14eeb30b3cc56c72ccdc310123bcdf53e0333e3f416a" # dogood |
| 68 | + [[users.capabilities]] |
| 69 | + action = "search" |
| 70 | + object = "ou=superheros,dc=glauth,dc=com" |
| 71 | +
|
| 72 | +[[users]] |
| 73 | + name = "johndoe" |
| 74 | + uidnumber = 5002 |
| 75 | + primarygroup = 5502 |
| 76 | + passsha256 = "6478579e37aff45f013e14eeb30b3cc56c72ccdc310123bcdf53e0333e3f416a" # dogood |
| 77 | +
|
| 78 | +[[users]] |
| 79 | + name = "serviceuser" |
| 80 | + mail = "serviceuser@example.com" |
| 81 | + uidnumber = 5003 |
| 82 | + passsha256 = "652c7dc687d98c9889304ed2e408c74b611e86a40caa51c4b43f1dd5913c5cd0" # mysecret |
| 83 | + primarygroup = 5502 |
| 84 | + [[users.capabilities]] |
| 85 | + action = "search" |
| 86 | + object = "*" |
| 87 | +
|
| 88 | +[[users]] |
| 89 | + name = "user4" |
| 90 | + uidnumber = 5003 |
| 91 | + primarygroup = 5504 |
| 92 | + othergroups = [5505, 5506] |
| 93 | + passsha256 = "652c7dc687d98c9889304ed2e408c74b611e86a40caa51c4b43f1dd5913c5cd0" # mysecret |
| 94 | + [[users.customattributes]] |
| 95 | + employeetype = ["Intern", "Temp"] |
| 96 | + employeenumber = [12345, 54321] |
| 97 | +
|
| 98 | +[[groups]] |
| 99 | + name = "superheros" |
| 100 | + gidnumber = 5501 |
| 101 | +
|
| 102 | +[[groups]] |
| 103 | + name = "svcaccts" |
| 104 | + gidnumber = 5502 |
| 105 | +
|
| 106 | +[[groups]] |
| 107 | + name = "civilians" |
| 108 | + gidnumber = 5503 |
| 109 | + includegroups = [ 5501 ] |
| 110 | +
|
| 111 | +[[groups]] |
| 112 | + name = "caped" |
| 113 | + gidnumber = 5504 |
| 114 | + includegroups = [ 5502, 5501 ] |
| 115 | +``` |
| 116 | +and LDAP should return these `memberOf` values: |
| 117 | +```text |
| 118 | +uid: hackers |
| 119 | +ou: superheros |
| 120 | +memberOf: cn=caped,ou=groups,dc=militate,dc=com |
| 121 | +memberOf: cn=civilians,ou=groups,dc=militate,dc=com |
| 122 | +memberOf: cn=superheros,ou=groups,dc=militate,dc=com |
| 123 | +
|
| 124 | +uid: johndoe |
| 125 | +ou: svcaccts |
| 126 | +memberOf: cn=caped,ou=groups,dc=militate,dc=com |
| 127 | +memberOf: cn=svcaccts,ou=groups,dc=militate,dc=com |
| 128 | +
|
| 129 | +uid: serviceuser |
| 130 | +ou: caped |
| 131 | +memberOf: cn=caped,ou=groups,dc=militate,dc=com |
| 132 | +
|
| 133 | +uid: user4 |
| 134 | +ou: caped |
| 135 | +memberOf: cn=caped,ou=groups,dc=militate,dc=com |
| 136 | +memberOf: cn=lovesailing,ou=groups,dc=militate,dc=com |
| 137 | +memberOf: cn=smoker,ou=groups,dc=militate,dc=com |
| 138 | +``` |
| 139 | +If you have the ldap client package installed, this can be easily confirmed by running |
| 140 | +``` |
| 141 | +ldapsearch -H ldap://localhost:3893 -D cn=hackers,ou=superheros,dc=glauth,dc=com -w dogood -x -bdc=glauth,dc=com cn=hackers |
| 142 | +``` |
| 143 | +and so on. |
| 144 | + |
| 145 | + |
| 146 | +### Discussion: database schema |
| 147 | + |
| 148 | +While GLAuth is not meant to support millions of user accounts, some decent performance is still expected! In fact, when searching through records using a database query, we should see a performance of O(log n) as opposed to, when searching through a flat config, O(n). |
| 149 | + |
| 150 | +While it would be friendlier to offer related attributes in `join`ed tables, we may end up re-creating a "browse" scenario unintentionally. |
| 151 | + |
| 152 | +For instance, when retrieving custom attributes, we could go through an attribute table: `custattr[userid, attribute, value#n]` |
| 153 | + |
| 154 | +However, this means that a `join` statement between the account table and the custom attribute table would yield the cartesian product of each account x attributes; we would need to iterate through the results and collate them. |
| 155 | + |
| 156 | +Alternatively, in Postgres and MySQL, we could rely on the database engine's built-in support for `crosstab` which pivots the second table's results into corresponding columns. This would not be supported in SQLite and would also mean building pretty nasty execution plans. |
| 157 | + |
| 158 | +**So, what's the decision?** |
| 159 | + |
| 160 | +In GLAuth 2.x, when including information that does not benefit from being normalized (e.g. custom attributes) we are following the "nosql" trend (irony!) of storing this data in a JSON structure. |
| 161 | + |
| 162 | +## PAM Plugin |
| 163 | + |
| 164 | +To authenticate against local users, edit the configuration file (see pkg/plugins/sample-pam.cfg) so that: |
| 165 | + |
| 166 | +``` |
| 167 | +... |
| 168 | +[backend] |
| 169 | + datastore = "plugin" |
| 170 | + plugin = "bin/pam.so" |
| 171 | +... |
| 172 | +``` |
| 173 | + |
| 174 | +When building this plugin, one must first ensure that the proper development headers are installed. For instance, on Ubuntu: |
| 175 | +``` |
| 176 | +sudo apt-get install libpam0g-dev |
| 177 | +``` |
| 178 | + |
| 179 | +You will likely also wish to tweak the `groupWithSearchCapability` setting, to assign an appropriate secondary group. |
| 180 | + |
| 181 | +Then, to perform a search: |
| 182 | +``` |
| 183 | +ldapsearch -LLL -H ldap://localhost:3893 -D cn=<unix user name>,ou=<a group the user belongs to>,dc=glauth,dc=com -w <unix user password> -x -bdc=glauth,dc=com cn=<unix user name> |
| 184 | +``` |
0 commit comments