Switch to unified view

a/Allura/allura/model/auth.py b/Allura/allura/model/auth.py
...
...
65
    then encoded as per normal.
65
    then encoded as per normal.
66
    """
66
    """
67
    return urllib.urlencode([i for i in generate_smart_str(params)])
67
    return urllib.urlencode([i for i in generate_smart_str(params)])
68
68
69
69
70
class ApiToken(MappedClass):
70
class ApiAuthMixIn(object):
71
    class __mongometa__:
72
        name='api_token'
73
        session = main_orm_session
74
        unique_indexes = [ 'user_id' ]
75
76
    _id = FieldProperty(S.ObjectId)
77
    user_id = ForeignIdProperty('User')
78
    api_key = FieldProperty(str, if_missing=lambda:h.nonce(20))
79
    secret_key = FieldProperty(str, if_missing=h.cryptographic_nonce)
80
    expires = FieldProperty(datetime, if_missing=None)
81
    capabilities = FieldProperty({str:str})
82
83
    user = RelationProperty('User')
84
71
85
    def authenticate_request(self, path, params):
72
    def authenticate_request(self, path, params):
86
        try:
73
        try:
87
            # Validate timestamp
74
            # Validate timestamp
88
            timestamp = iso8601.parse_date(params['api_timestamp'])
75
            timestamp = iso8601.parse_date(params['api_timestamp'])
89
            timestamp_utc = timestamp.replace(tzinfo=None) - timestamp.utcoffset()
76
            timestamp_utc = timestamp.replace(tzinfo=None) - timestamp.utcoffset()
90
            if self.expires and datetime.utcnow() > self.expires:
91
                return False
92
            if abs(datetime.utcnow() - timestamp_utc) > timedelta(minutes=10):
77
            if abs(datetime.utcnow() - timestamp_utc) > timedelta(minutes=10):
93
                return False
78
                return False
94
            # Validate signature
79
            # Validate signature
95
            api_signature = params['api_signature']
80
            api_signature = params['api_signature']
96
            params = sorted((k,v) for k,v in params.iteritems() if k != 'api_signature')
81
            params = sorted((k,v) for k,v in params.iteritems() if k != 'api_signature')
...
...
113
        if not has_api_signature:
98
        if not has_api_signature:
114
            string_to_sign = path + '?' + urlencode(sorted(params))
99
            string_to_sign = path + '?' + urlencode(sorted(params))
115
            digest = hmac.new(self.secret_key, string_to_sign, hashlib.sha256)
100
            digest = hmac.new(self.secret_key, string_to_sign, hashlib.sha256)
116
            params.append(('api_signature', digest.hexdigest()))
101
            params.append(('api_signature', digest.hexdigest()))
117
        return params
102
        return params
103
104
    def get_capability(self, key):
105
        return None
106
107
108
class ApiToken(MappedClass, ApiAuthMixIn):
109
    class __mongometa__:
110
        name='api_token'
111
        session = main_orm_session
112
        unique_indexes = [ 'user_id' ]
113
114
    _id = FieldProperty(S.ObjectId)
115
    user_id = ForeignIdProperty('User')
116
    api_key = FieldProperty(str, if_missing=lambda:h.nonce(20))
117
    secret_key = FieldProperty(str, if_missing=h.cryptographic_nonce)
118
119
    user = RelationProperty('User')
120
121
    @classmethod
122
    def get(cls, api_key):
123
        return cls.query.get(api_key=api_key)
124
125
126
class ApiTicket(MappedClass, ApiAuthMixIn):
127
    class __mongometa__:
128
        name='api_ticket'
129
        session = main_orm_session
130
    PREFIX = 'tck'
131
132
    _id = FieldProperty(S.ObjectId)
133
    user_id = ForeignIdProperty('User')
134
    api_ticket = FieldProperty(str, if_missing=lambda: ApiTicket.PREFIX + h.nonce(20))
135
    secret_key = FieldProperty(str, if_missing=h.cryptographic_nonce)
136
    expires = FieldProperty(datetime, if_missing=None)
137
    capabilities = FieldProperty({str:str})
138
139
    user = RelationProperty('User')
140
141
    @classmethod
142
    def get(cls, api_ticket):
143
        if not api_ticket.startswith(cls.PREFIX):
144
            return None
145
        return cls.query.get(api_ticket=api_ticket)
146
147
    def authenticate_request(self, path, params):
148
        if self.expires and datetime.utcnow() > self.expires:
149
            return False
150
        return ApiAuthMixIn.authenticate_request(self, path, params)
151
152
    def get_capability(self, key):
153
        return self.capabilities.get(key)
118
154
119
class EmailAddress(MappedClass):
155
class EmailAddress(MappedClass):
120
    re_format = re.compile('^.* <(.*)>$')
156
    re_format = re.compile('^.* <(.*)>$')
121
    class __mongometa__:
157
    class __mongometa__:
122
        name='email_address'
158
        name='email_address'