Exemple #1
0
class FilterRule(Model):
    """
	Filter Rule
	"""
    user = property.ReferenceProperty(User)
    path = property.StringProperty(default="*")
    method = property.StringProperty(default="*")

    weight = property.IntegerProperty()

    input_filter = property.BlobProperty()
    output_filter = property.BlobProperty()
Exemple #2
0
class Post(Model):
    """
	Representation of a blog post
	"""
    title = property.StringProperty(verbose_name="Title")
    date = property.DateTimeProperty(auto_now_add=True)
    author = property.ReferenceProperty(User, collection_name="posts")
    contents = property.BlobProperty(verbose_name="Entry")
Exemple #3
0
class Authorization(Model):
    """Authorization Grant"""
    auth_group = property.StringProperty(verbose_name="Authorization Group")
    method = property.StringProperty(
        default="*",
        verbose_name="Permission",
        choices=["*", "GET", "POST", "PUT", "DELETE"])
    obj_name = property.StringProperty(default="", verbose_name="Object Name")
    prop_name = property.StringProperty(default="",
                                        verbose_name="Property Name")

    def put(self):
        """These need to be unique, so if we don't have an ID we
		search for another authorization with all the same properties"""
        if not self.id:
            for obj in self.find(auth_group=self.auth_group,
                                 method=self.method,
                                 obj_name=self.obj_name,
                                 prop_name=self.prop_name):
                self.id = obj.id
                break
        Model.put(self)
Exemple #4
0
class User(Model):
    """Simple user object"""
    username = property.StringProperty(verbose_name="Username", unique=True)
    name = property.StringProperty(verbose_name="Name")
    _indexed_name = property.StringProperty()
    email = property.StringProperty(verbose_name="Email Address")
    phone = property.StringProperty(
        verbose_name="Phone Number")  # Used for SMS notify
    auth_groups = property.ListProperty(str,
                                        verbose_name="Authorization Groups")
    password = property.PasswordProperty(verbose_name="Password")
    auth_token = property.StringProperty(verbose_name="Authentication Token")
    oid = property.StringProperty(verbose_name="OpenID")
    authorizations = None

    # These fields are easy to add in
    created_at = property.DateTimeProperty(auto_now_add=True,
                                           verbose_name="Created Date")
    modified_at = property.DateTimeProperty(verbose_name="Last Modified Date")
    deleted = property.BooleanProperty(verbose_name="Deleted")
    deleted_at = property.DateTimeProperty(verbose_name="Deleted Date")
    sys_modstamp = property.DateTimeProperty(auto_now=True)

    def __str__(self):
        return self.name

    def notify(self, subject, body='', **params):
        """Send notification to this user

		@param subject: Subject for this notification
		@type subject: str

		@param body: The message to send you
		@type body: str
		"""
        import boto.utils
        boto.utils.notify(subject=subject,
                          html_body=body,
                          to_string=self.email,
                          append_instance_id=False,
                          **params)

    def sms(self, msg):
        """Sends an SMS message via Twilio
		This requires the following boto configuration:
		[Twilio]
		from = <from phone>
		account_id = <account id>
		auth_token = <authentication token>"""
        from botoweb.exceptions import BadRequest
        import urllib2, urllib
        import boto
        account_id = boto.config.get("Twilio", "account_id")
        auth_token = boto.config.get("Twilio", "auth_token")
        from_phone = boto.config.get("Twilio", "from")
        if not account_id or not auth_token or not from_phone:
            raise BadRequest("Twilio configuration not set up")
        if not self.phone:
            raise BadRequest("No phone number set up")
        url = SMS_URL % account_id
        pwmgr = urllib2.HTTPPasswordMgrWithDefaultRealm()
        pwmgr.add_password(None, "https://api.twilio.com/", account_id,
                           auth_token)
        handler = urllib2.HTTPBasicAuthHandler(pwmgr)
        opener = urllib2.build_opener(handler)
        values = {"From": from_phone, "To": self.phone, "Body": msg}
        data = urllib.urlencode(values)
        request = urllib2.Request(url, data)
        response = opener.open(request)
        return response.read()

    def generate_password(self,
                          length=10,
                          digits=True,
                          loweralpha=True,
                          upperalpha=True):
        """Generate and return a random password
		:param length: the optional length of the password (default 10
		:type length: int
		"""
        try:
            import boto, urllib2
            if digits:
                digits = "on"
            else:
                digits = "off"
            if loweralpha:
                loweralpha = "on"
            else:
                loweralpha = "off"
            if upperalpha:
                upperalpha = "on"
            else:
                upperalpha = "off"

            url = "https://www.random.org/cgi-bin/randstring?num=1&len=%s&digits=%s&upperalpha=%s&loweralpha=%s&unique=on&format=text&rnd=new" % (
                length, digits, upperalpha, loweralpha)
            headers = {
                "User-Agent":
                "%s %s (%s)" % (boto.config.get("app", "name", "botoweb"),
                                boto.config.get("app", "version", "0.1"),
                                boto.config.get("app", "admin_email", ""))
            }
            req = urllib2.Request(url, None, headers)
            hand = urllib2.urlopen(req)
            return hand.read().strip()
        except:
            import boto, uuid
            boto.log.exception(
                "Exception generating random entropy for Auth Token from Random.org"
            )
            return str(uuid.uuid4()).replace("-", "")

    def send_password(self, app_link):
        """Send the user a random password"""
        import boto
        passwd = self.generate_password()
        self.password = passwd
        self.put()
        args = {
            "appname": boto.config.get("app", "name", "botoweb"),
            "applink": app_link,
            "password": passwd,
            "name": self.name,
            "username": self.username
        }
        self.notify(
            "[%s] Password Reset" % boto.config.get("app", "name", "botoweb"),
            PASSWORD_TEMPLATE % args)

    def send_auth_token(self,
                        app_link,
                        app_name=None,
                        subject="Account Created",
                        args={}):
        """Send the user an auth-token link, allowing them to 
		set up their own login using JanRain Authentication"""
        import boto
        self.auth_token = self.generate_password(length=20)
        self.put()
        if not app_name:
            app_name = boto.config.get("app", "name", "botoweb")
        args["appname"] = app_name
        args["link"] = "%s?auth_token=%s" % (app_link, self.auth_token)
        args["name"] = self.name
        args["username"] = self.username
        return self.notify(subject, CREATED_TEMPLATE % args)

    def has_auth_group(self, group):
        return (group in self.auth_groups)

    def has_auth_group_ctx(self, ctx, group):
        return self.has_auth_group(group)

    def load_auths(self):
        """Load up all the authorizations this user has"""
        from botoweb.resources.authorization import Authorization
        self.authorizations = {"*": {"*": {"*": False}}, "": {"": {"": False}}}
        if self.auth_groups:
            query = Authorization.find(auth_group=self.auth_groups)
            for auth in query:
                if not self.authorizations.has_key(auth.method):
                    self.authorizations[auth.method] = {}
                if not self.authorizations[auth.method].has_key(auth.obj_name):
                    self.authorizations[auth.method][auth.obj_name] = {}
                self.authorizations[auth.method][auth.obj_name][
                    auth.prop_name] = True

                # Weird indexing to say "Yes, they have a value here somewhere"
                if not self.authorizations[auth.method].has_key(""):
                    self.authorizations[auth.method][""] = {}
                if not self.authorizations[""].has_key(auth.obj_name):
                    self.authorizations[""][auth.obj_name] = {"": True}
                self.authorizations[""][""][""] = True
                self.authorizations[""][""][auth.prop_name] = True
                self.authorizations[""][auth.obj_name][""] = True
                self.authorizations[""][auth.obj_name][auth.prop_name] = True
                self.authorizations[auth.method][auth.obj_name][""] = True
                self.authorizations[auth.method][""][auth.prop_name] = True
                self.authorizations[auth.method][""][""] = True

        return self.authorizations

    def has_auth(self, method="", obj_name="", prop_name=""):
        if self.has_auth_group("admin"):
            return True
        if not self.authorizations:
            self.load_auths()

        method = method.upper()
        if not self.authorizations.has_key(method):
            method = "*"
        if not self.authorizations[method].has_key(obj_name):
            obj_name = "*"
            if not self.authorizations[method].has_key(obj_name):
                return False
        if not self.authorizations[method][obj_name].has_key(prop_name):
            prop_name = "*"
            if not self.authorizations[method][obj_name].has_key(prop_name):
                return False
        return self.authorizations[method][obj_name][prop_name]

    def has_auth_ctx(self, ctx, method="", obj_name="", prop_name=""):
        if isinstance(method, list):
            method = method[0]
        if isinstance(obj_name, list):
            obj_name = obj_name[0]
        if isinstance(prop_name, list):
            prop_name = prop_name[0]
        if isinstance(obj_name,
                      object) and obj_name.__class__.__name__ == "_Element":
            obj_name = obj_name.tag
        method = method.upper()
        if method == "HEAD":
            method = "GET"
        if method == "OPTIONS":
            method = "GET"
        return self.has_auth(method=method,
                             obj_name=obj_name,
                             prop_name=prop_name)

    def matches(self, val):
        return val in (self.username, self.id, self.name)

    def matches_ctx(self, ctx, val):
        if isinstance(val, list):
            for v in val:
                if self.matches_ctx(ctx, v):
                    return True
            return False
        if isinstance(val, object) and val.__class__.__name__ == "_Element":
            val = val.get("id")
        return self.matches(val)

    def put(self):
        """Auto-index"""
        self._indexed_name = self.name.upper().strip()
        return Model.put(self)

    def to_dict(self, *args, **kwargs):
        """Get this object as a simple dict, to be serialized.
		This just adds in the authorizations in addition to the
		rest of the object that is serialized via Model.to_dict"""
        ret = Model.to_dict(self, *args, **kwargs)
        if not self.authorizations:
            self.load_auths()
        ret['authorizations'] = self.authorizations
        return ret

    @classmethod
    def from_dict(cls, data):
        """Load this object from a dict, as exported
		by to_dict"""
        ret = super(User, cls).from_dict(data)
        ret.authorizations = data.get('authorizations')
        return ret