def _registerClient(self, request): (appchange, script, args, myId) = yield self._getBasicArgs(request) landing = not self._ajax myOrgId = args["orgId"] name = utils.getRequestArg(request, "name") desc = utils.getRequestArg(request, "desc") scope = utils.getRequestArg(request, "scope", multiValued=True) category = utils.getRequestArg(request, "category") redirect = utils.getRequestArg(request, "redirect", sanitize=False) if not name: raise errors.MissingParams(["Name"]) if not scope: raise errors.MissingParams(["Permissions"]) if category != "apikey" and not redirect: raise errors.MissingParams(["Redirect URL"]) knownScopes = globals().get("scopes") unknownScopes = [x for x in scope if x not in knownScopes.keys()] if category not in ["webapp", "native", "apikey"] or unknownScopes: raise errors.BaseError("Invalid value sent for Type/Permissions") clientId = utils.getUniqueKey() clientSecret = utils.getRandomKey() meta = { "author": myId, "name": name, "org": myOrgId, "secret": utils.hashpass(clientSecret), "scope": " ".join(scope), "category": category, } if category != "apikey": meta["redirect"] = b64encode(redirect) meta["desc"] = desc yield db.batch_insert(clientId, "apps", {"meta": meta}) yield db.insert(myId, "appsByOwner", "", clientId) yield db.insert(myOrgId, "appsByOwner", "", clientId) else: yield db.batch_insert(clientId, "apps", {"meta": meta}) yield db.insert(myId, "entities", "", clientId, "apikeys") self.setTitle(request, name) args["clientId"] = clientId args["client"] = meta args["client"]["secret"] = clientSecret t.renderScriptBlock(request, "apps.mako", "registrationResults", landing, "#apps-contents", "set", **args)
def _secret(self, request): myId = request.getSession(IAuthInfo).username clientId = utils.getRequestArg(request, "id", sanitize=False) client = yield db.get_slice(clientId, "apps") client = utils.supercolumnsToDict(client) if not client: raise errors.InvalidApp(clientId) if client["meta"]["author"] != myId: raise errors.AppAccessDenied(clientId) clientSecret = utils.getRandomKey() yield db.insert(clientId, "apps", utils.hashpass(clientSecret), "secret", "meta") args = {"clientId": clientId, "client": client["meta"], "info": "New application secret was generated"} args["client"]["secret"] = clientSecret t.renderScriptBlock(request, "apps.mako", "registrationResults", False, "#apps-contents", "set", **args)
def _sendSignupInvitation(emailId): if len(emailId.split('@')) != 2: raise InvalidEmailId() mailId, domain = emailId.split('@') if domain in blacklist: raise DomainBlacklisted() rootUrl = config.get('General', 'URL') brandName = config.get('Branding', 'Name') signature = "Flocked-in Team.\n\n\n\n" myOrgId = yield getOrgId(domain) if myOrgId: entities = yield db.get_slice(myOrgId, "entities", ["basic"]) myOrg = utils.supercolumnsToDict(entities) orgName = myOrg['basic']['name'] else: orgName = domain existing = yield db.get_slice(emailId, "userAuth", ["user"]) existing = utils.columnsToDict(existing) if existing and existing.get('user', ''): subject = "[%s] Account exists" % (brandName) body = "You already have an account on %(brandName)s.\n"\ "Please visit %(rootUrl)s/signin to sign-in.\n\n" textBody = (body + signature) % locals() htmlBody = t.getBlock("emails.mako", "accountExists", **locals()) else: subject = "Welcome to %s" % (brandName) body = "Please click the following link to join %(orgName)s network on %(brandName)s\n"\ "%(activationUrl)s\n\n" activationTmpl = "%(rootUrl)s/signup?email=%(emailId)s&token=%(token)s" token = utils.getRandomKey() insert_d = db.insert(domain, "invitations", emailId, token, emailId) activationUrl = activationTmpl % locals() textBody = (body + signature) % locals() htmlBody = t.getBlock("emails.mako", "signup", **locals()) yield insert_d yield utils.sendmail(emailId, subject, textBody, htmlBody)
def request_resetPassword(self, request): email = utils.getRequestArg(request, 'email') if not email: raise MissingParams(['']) now = time.time() validEmail, tokens, deleteTokens, leastTimestamp = yield _getResetPasswordTokens(email) if len(tokens) >= 10: delta = datetime.fromtimestamp(leastTimestamp + 86399) - datetime.fromtimestamp(now) hours = 1 + delta.seconds / 3600 raise PermissionDenied('We detected ususual activity from your account.<br/> Click the link sent to your emailId to reset password or wait for %s hours before you retry' % (hours)) if validEmail: token = utils.getRandomKey() yield db.insert(email, "userAuth", token, 'resetPasswdToken:%s' % (token), ttl=86400) yield _sendmailResetPassword(email, token) args = {"view": "forgotPassword-post"} t.render(request, "signup.mako", **args)
def _reportUser(self, request, myId, targetId): entities = base.EntitySet([myId, targetId]) yield entities.fetchData() reportedBy = entities[myId].basic["name"] email = entities[targetId].basic["emailId"] rootUrl = config.get('General', 'URL') brandName = config.get('Branding', 'Name') authinfo = request.getSession(IAuthInfo) amIAdmin = authinfo.isAdmin cols = yield db.get_slice(email, "userAuth", ["reactivateToken", "isFlagged", "isAdmin"]) cols = utils.columnsToDict(cols) if cols.has_key("isAdmin") and not amIAdmin: raise errors.PermissionDenied("Only administrators can flag other \ administrators for verification") if cols.has_key("isFlagged"): token = cols.get("reactivateToken") else: token = utils.getRandomKey() yield db.insert(email, "userAuth", token, 'reactivateToken') yield db.insert(email, "userAuth", "", 'isFlagged') body = "%(reportedBy)s has flagged your account for verification."\ "You can verify your account by clicking on the link below.\n"\ "\n\n%(reactivateUrl)s\n\n" reactivateUrl = "%(rootUrl)s/password/verify?email=%(email)s&token=%(token)s"%(locals()) args = {"brandName": brandName, "rootUrl": rootUrl, "reportedBy":reportedBy, "reactivateUrl": reactivateUrl} subject = "[%(brandName)s] Your profile has been flagged for review" %(locals()) htmlBody = t.getBlock("emails.mako", "reportUser", **args) textBody = body %(locals()) yield utils.sendmail(email, subject, textBody, htmlBody) request.write('$$.alerts.info("%s");' % _('User has been flagged for verification'))
def _tokenForClientCredentials(self, request): clientId = utils.getRequestArg(request, 'client_id') clientSecret = utils.getRequestArg(request, 'client_secret') client = yield db.get_slice(clientId, "apps") client = utils.supercolumnsToDict(client) if not client or not utils.checkpass(clientSecret, client['meta']['secret']): self._error(request, "invalid_client") return # The client is valid. Issue auth token. # We don't issue a refresh token and everytime the client will have # to authenticate using it's credentials scopes = client["meta"]["scope"].split(' ') userId = client["meta"]["author"] orgId = client["meta"]["org"] accessToken = utils.getRandomKey() accessTokenData = {"user_id": userId, "type": "access", "org_id": orgId, "client_id": clientId, "scope": " ".join(scopes)} yield db.batch_insert(accessToken, "oAuthData", accessTokenData, ttl=self._accessTokenExpiry) self._success(request, accessToken)
def _receiveUserAccess(self, request): authinfo = request.getSession(IAuthInfo) myId = authinfo.username myOrgId = authinfo.organization allow = utils.getRequestArg(request, 'allow') == "true" state = utils.getRequestArg(request, 'state') scopes = utils.getRequestArg(request, 'scope') clientId = utils.getRequestArg(request, 'client_id') redirectUri = utils.getRequestArg(request, 'redirect_uri', sanitize=False) signature = utils.getRequestArg(request, 'signature') # Check if signature is valid message = "%s:%s:%s:%s:%s" % \ (myId, clientId, scopes, redirectUri, state) checksum = hmac.new(myOrgId, message, hashlib.sha256) if signature != checksum.hexdigest(): self._error(request, self.SIGNATURE_MISMATCH) return client = yield db.get_slice(clientId, "apps") client = utils.supercolumnsToDict(client) if not client: self._error(request, self.CLIENT_GONE) return if allow: # Authcode must expire shortly after it is issued # We expire the authcode in 5 minutes? authCode = utils.getRandomKey() authMap = {"user_id": myId, "org_id": myOrgId, "client_id": clientId, "redirect_uri": b64encode(redirectUri), "scope": scopes, "type": "auth"} yield db.batch_insert(authCode, "oAuthData", authMap, ttl=120) yield db.insert(myId, "entities", authCode, clientId, "apps", ttl=120) self._redirectOnSuccess(request, redirectUri, authCode, state) else: self._redirectOnError(request, redirectUri, "access_denied", state)
def _tokenForAuthCode(self, request, refresh=False): clientId = utils.getRequestArg(request, 'client_id') clientSecret = utils.getRequestArg(request, 'client_secret') redirectUri = utils.getRequestArg(request, 'redirect_uri', sanitize=False) scopes = utils.getRequestArg(request, 'scope') if refresh: authCode = utils.getRequestArg(request, 'refresh_token') else: authCode = utils.getRequestArg(request, 'code') # XXX: We should be checking for HTTP authentication before # throwing an error in case of missing clientId and clientSecret. if not all([redirectUri, clientId, clientSecret, authCode]): self._error(request, "invalid_request") return grant = yield db.get_slice(authCode, "oAuthData") grant = utils.columnsToDict(grant) if not grant or grant['client_id'] != clientId or\ grant['redirect_uri'] != b64encode(redirectUri) or\ not (grant['type'] == 'auth' and not refresh or\ grant['type'] == 'refresh' and refresh): self._error(request, "invalid_grant") return grantedScopes = grant['scope'].split(' ') if scopes: scopes = scopes.split(' ') if [x for x in scopes if x not in grantedScopes]: self._error(request, "invalid_scope") return else: scopes = grantedScopes client = yield db.get_slice(clientId, "apps") client = utils.supercolumnsToDict(client) if not client or not utils.checkpass(clientSecret, client['meta']['secret']): self._error(request, "invalid_client") return userId = grant["user_id"] orgId = grant["org_id"] accessToken = utils.getRandomKey() accessTokenData = {"user_id": userId, "org_id": orgId, "type": "access", "client_id": clientId, "auth_code": authCode, "scope": " ".join(scopes)} yield db.batch_insert(accessToken, "oAuthData", accessTokenData, ttl=self._accessTokenExpiry) refreshToken = utils.getRandomKey() refreshTokenData = {"user_id": userId, "org_id": orgId, "type": "refresh", "client_id": clientId, "redirect_uri": grant["redirect_uri"], "auth_code": authCode, "scope": grant["scope"]} yield db.batch_insert(refreshToken, "oAuthData", refreshTokenData, ttl=self._refreshTokenExpiry) yield db.insert(userId, "entities", refreshToken, clientId, "apps", ttl=self._refreshTokenExpiry) yield db.remove(authCode, "oAuthData") self._success(request, accessToken, refreshToken)
def _sendInvitations(myOrgUsers, otherOrgUsers, me, myId, myOrg): rootUrl = config.get('General', 'URL') brandName = config.get('Branding', 'Name') senderName = me.basic["name"] senderOrgName = myOrg.basic["name"] senderAvatarUrl = utils.userAvatar(myId, me, "medium") sentUsers = [] blockedUsers = [] existingUsers = [] myOrgSubject = "%s invited you to %s" % (senderName, brandName) myOrgBody = "Hi,\n\n"\ "%(senderName)s has invited you to %(senderOrgName)s network on %(brandName)s.\n"\ "To activate your account please visit: %(activationUrl)s.\n\n" otherOrgSubject = "%s invited you to %s" % (senderName, brandName) otherOrgBody = "Hi,\n\n"\ "%(senderName)s has invited you to try %(brandName)s.\n"\ "To activate your account please visit: %(activationUrl)s.\n\n" signature = "Flocked.in Team.\n\n\n\n"\ "--\n"\ "To block invitations from %(senderName)s visit %(blockSenderUrl)s\n"\ "To block all invitations from %(brandName)s visit %(blockAllUrl)s" blockSenderTmpl = "%(rootUrl)s/signup/blockSender?email=%(emailId)s&token=%(token)s" blockAllTmpl = "%(rootUrl)s/signup/blockAll?email=%(emailId)s&token=%(token)s" activationTmpl = "%(rootUrl)s/signup?email=%(emailId)s&token=%(token)s" # Combine all users. myOrgUsers.extend(otherOrgUsers) # Ensure that the users do not already exist and that the users are # not in the doNotSpam list (for this sender or globally) d1 = db.multiget(myOrgUsers, "userAuth", "user") d2 = db.multiget_slice(myOrgUsers, "doNotSpam", [myId, '*']) existing = yield d1 existing = utils.multiColumnsToDict(existing) doNotSpam = yield d2 doNotSpam = utils.multiColumnsToDict(doNotSpam) deferreds = [] for emailId in myOrgUsers: if emailId in existing and existing[emailId]: existingUsers.append(emailId) continue token = utils.getRandomKey() # Add invitation to the database localpart, domainpart = emailId.split('@') deferreds.append(db.insert(domainpart, "invitations", myId, token, emailId)) deferreds.append(db.insert(myId, "invitationsSent", '', emailId)) # Mail the invitation if everything is ok. if emailId in doNotSpam and doNotSpam[emailId]: blockedUsers.append(emailId) continue activationUrl = activationTmpl % locals() blockAllUrl = blockAllTmpl % locals() blockSenderUrl = blockSenderTmpl % locals() sameOrg = False if emailId in otherOrgUsers else True if not sameOrg: subject = otherOrgSubject textBody = (otherOrgBody + signature) % locals() else: subject = myOrgSubject textBody = (myOrgBody + signature) % locals() # XXX: getBlock blocks the application for disk reads when reading template htmlBody = t.getBlock("emails.mako", "invite", **locals()) deferreds.append(utils.sendmail(emailId, subject, textBody, htmlBody)) sentUsers.append(emailId) yield defer.DeferredList(deferreds) defer.returnValue((sentUsers, blockedUsers, existingUsers))