github.com/wostzone/hub/auth@v0.0.0-20220118060317-7bb375743b17/README.md (about) 1 # hubauth 2 3 ## Objective 4 5 Single sign-on with access control for users to access Hub services. 6 7 ## Status 8 9 The status of this plugin is alpha. It is functional but breaking changes are expected. 10 11 ## Audience 12 13 This project is aimed at IoT developers that value the security and interoperability that WoST brings. WoST Things are 14 more secure than traditional IoT devices as they do not run a server, but instead connect to a Hub to publish their 15 information and receive actions. 16 17 ## Summary 18 19 This service provides authentication and authorization for services and their clients. All requests to the various Hub 20 services requires authentication by the Auth service. 21 22 Login provides the user with a pair of JWT tokens that can be used to authenticate at all services. Access tokens have a 23 short lifetime and must be refreshed using the refresh token before they expire. 24 25 This provides a 26 27 * Authentication service for... 28 * Providing access and refresh tokens using the users login credentials 29 * Refreshing user access/refresh token pair 30 * Creating username/password by administrator 31 * Changing of the user password 32 33 * Library for validating access token by services 34 35 * Commandline utility to manage users, change passwords (by administrator) and generate certificates. 36 37 ### Certificate Generation 38 39 The hubauth module generates the following certificates and stores then in the Hub 'certs' folder. 40 41 1. The CA certificate and private key is generated on first startup, as a self-signed certificate. The CA certficate is 42 shared with every client and server and is used to verify authenticity of all other certificates. The CA key is only 43 used to generate the certificates listed here. Intermediary certificates are not used by WoST Hub services. 44 2. The hub certificate and key are regenerated on each startup using the CA certificate. This certificate is used by hub 45 services such as the provisioning server (idprov), directory server (thingdir), and mosquitto message bus server. The 46 keys of this certificate is used to generate and validate access and refresh tokens. 47 3. The plugin certificate and key are regenerated on each startup using the CA certificate. This client certificate is 48 used by hub services to authenticate access other hub services, like for example the message bus. 49 4. IoT Device client certificates are generated by the IDProv provisioning server using the client's public key. These 50 certificates include the OU 'things' and are only issued to IoT devices that publish Thing information. 51 52 A commandline utility can generate custom certificates for special users such as administrators. All services accept 53 certificates signed by the CA. 54 55 ### Client Certificate Authentication 56 57 Authentication through client certificates is handled by the TLS protocol itself. A valid certificate is required in 58 order to make a connection. The certificate CN contains the user or service name, the OU is used to indicate the role in 59 the organization. 60 61 * Hub plugins use the hub client certificate to access other Hub services. The Hub plugin certificate contains 'plugin' 62 as the OU which is used to authorize full access. 63 * IoT devices have the device-ID as the CN and 'iotdevice' as the OU. IoT devices are publishers of things and have 64 access to all Things of which they are the publisher. 65 * The administrator certificate has their user loginID as the CN and 'admin' as the OU. 66 * Other clients have their loginID as the CN and 'client' as the OU. 67 68 Properly signed certificates are always accepted as valid authentication. Their OU are used in authorization. 69 70 ### Username/password Authentication 71 72 Unpw authentication is used for users that connect through a web client or mobile application. Clients use the auth API 73 with their login ID and password to obtain a pair of tokens that are needed to use the service API. To change a password 74 a valid password is also needed. 75 76 Administrators manage users and passwords through the 'auth' commandline utility or through the auth API. Creating users 77 or resetting passwords requires an 'admin' client certificate authentication. 78 79 #### **Password Storage** 80 81 Passwords are stored by the service using argon2id hashing. This is chosen as it is one of the strongest hash algorithms 82 that is resistant to GPU cracking attacks and side channel 83 attacks. [See wikipedia](https://en.wikipedia.org/wiki/Argon2). In future other algorithms can be supported as needed. 84 85 #### **Token Generation** 86 87 Unpw authentication uses JWT with H256 hashing for access and refresh token generation. Hashing protocol negotiation is 88 not 89 allowed [as this is considered a weakness](https://auth0.com/blog/critical-vulnerabilities-in-json-web-token-libraries/) 90 . The required hashing algorithm can be changed without notice but is dictated by the server. JWT is chosen as it 91 secures a set of 'claims' which includes the userID. The userID is needed for authorization of a request. The hub 92 private key is used as the secret shared amongst plugin services. It is regenerated on each restart of the hub ( 93 requiring a new login). The JWT header includes the hashing algorithm which MUST match the algorithm service is 94 configured for before token verification takes place. 95 96 Clients request an access/refresh token-pair from the auth service endpoint by providing a login ID and a secret ( 97 password). The refresh token can be used to obtain a new set of access/refresh tokens. This approach allows for 98 stateless verification of the access token for its (configurable) validity period with a default of 1 hour. The refresh 99 token is valid for a longer with a default of two weeks. After the token expires, the user has to login to obtain a new 100 token pair. Until then no login is required. Refresh tokens are stored in secure client cookies which means they are not 101 accessible by clients and each applicatino must must login separately. Once logged in refresh tokens are used to avoid 102 unnecesary logins. 103 104 Access and refresh tokens include claim with the IP address of the sender, which must match during verification. Any 105 attempt to use the tokens with a different IP fails. The refresh token will be invalidated if an IP mismatch is detected 106 even if it hasn't expired yet. 107 108 All Hub services accept the access token within its validity period. Services verify the access token and its claims 109 using the server certificate key which all services have access to. Since a restart of the hub regenerates this key, 110 access and refresh tokens are invalidated at a Hub restart. 111 112 In short, services perform stateless verification of access tokens and return unauthorized if the token is expired or 113 doesn't match the IP address of the sender. Clients must refresh their tokens if they receive an unauthorized response 114 from one of the services and retry the request. 115 116 Weakness: Access to the tokens is the achilles heel of this approach. If a bad actor obtains a token while it is still 117 valid, and can spoof its IP address to that of the token, then security is compromised. 118 119 ## Authorization 120 121 The auth module provides a library to assist services with handling authorizing requests. 122 123 Hub authorization groups things together and lets users view or control those things. This makes is easy to give 124 multiple users access to the same set of Things and at the same time simplifies access management of things. 125 126 Hub authorization is based on roles in groups that are centrally managed by the auth module: 127 128 1. Plugins have full authorization and access to all Things on the Hub 129 2. Users only have access to Things in the same group, based on their role: 130 - view role gives read access to Things 131 - control role lets the user control things 132 - manage role lets the user configure things 133 - admin role has full access 134 - thing role is for things only and lets the thing manage itself 135 136 The 'all' group is built-in and automatically includes all Things. To allow a user to view all Things, the loginID is 137 added to the all group with the 'view' role. 138 139 A future considerations is to automatically create groups based on Thing Type, for example a group of environmental 140 sensors. This further simplifies group creation as things are automatically added to the groups they serve. This 141 requires a good consistent vocabulary of Thing types which is still tbd. 142 143 ### Group Management 144 145 Things, users, groups and roles are defined in the ACL store. The first store implementation is a file that is loaded in 146 memory. The auth commandline lets the administrator add and remove users from the group. A REST API for managing groups 147 is planned. 148 149 The client library automatically reloads the file if it is modified. 150 151 To authorize a request, the client library needs to know the login-ID of the user, thing-ID to access, read/write 152 operation to perform and in case of writing the message type to write. These write message types are the Thing 153 Description document (TD), values update, action, event, and configuration. 154 155 The role permissions for these actions are: 156 157 | Role | TD | Configure | Values | Event | Action 158 |--------|-------| --------- | ------- | -------| ------- 159 | view | read | - | read | read | - 160 | control| read | - | read | read | write 161 | manage | read | write | read | read | write 162 | admin | read | write | read | read | write 163 | thing | write | read | write | write | write 164 | plugin | write | write | write | write | write 165 166 ## Build and Installation 167 168 ### Build & Install (tentative) 169 170 Run 'make all' to build and 'make install' to install as a user. 171 172 See [hub's README.md](https://github.com/wostzone/hub/README.md) for more details. 173 174 ## Usage 175 176 Code below is pseudocode and needs to be updated. 177 178 ### User login 179 180 ```golang 181 authClient := NewAuthClient(address, port) 182 accessToken, err := authClient.Login(username, password) 183 // login sets the refresh token in a secure cookie. 184 ``` 185 186 ### User refresh auth tokens 187 188 ```golang 189 authClient := NewAuthClient(address, port) 190 // The refresh token was stored in a secure cookie. 191 accessToken, err := authClient.Refresh() 192 if err != nil { 193 // if token cannot be refreshed then request user login 194 } 195 ``` 196 197 ### Server validates token (authenticate) 198 199 Access tokens can be validated stateless as long as we know to verification secret 200 201 ```golang 202 secret := ReadPrivateKey(file) 203 authClient := NewAuthClient(secret) 204 claims, err := authClient.VerifyToken(accessToken) 205 if err != nil { 206 return unauthorized 207 } 208 ``` 209 210 ### Server authorizes user 211 212 Authorization keeps the ACL store in memory. 213 214 * loginID is the user login ID when authenticated with password 215 * ou is the user OU when authenticated using a client certificate 216 * thingID is the thing to access 217 * writing is read (false) or write (true) access 218 * writeType is the type of record to write, eg TD, Action, Event, Config, ... 219 220 ```golang 221 thing1ID := "urn:zone1:publisher1:thing1" 222 loginID := "user1" 223 ou := "" // from client certificate if used 224 writing := false 225 writeType := MessageTypeTD 226 aclStore := aclstore.NewAclFileStore(aclFilePath, PluginID) 227 az := authorize.NewAuthorizer(aclStore) 228 az.VerifyAuthorization(loginID, ou, thingID, writing, writeType) 229 ``` 230 231 ### Administrator adds user to group 232 233 To allow a user to view things in group 'temperature' 234 235 ```golang 236 groupName := "temperature" 237 aclStore := aclstore.NewAclFileStore(aclFilePath, PluginID) 238 aclStore.SetRole(loginID, groupName, authorize.GroupRoleViewer) 239 ``` 240 241 Or editing the acl file directly: 242 243 > groups.yaml 244 245 ```yaml 246 all: 247 admin: GroupRoleManager 248 249 temperature: 250 user1: GroupRoleViewer 251 urn:zone1:publisher1:thing1: ThingRole 252 urn:zone1:publisher1:thing2: ThingRole 253 ```