Skip to content

Commit 212fc67

Browse files
authored
Merge pull request #8 from pyobs/develop
v1.2
2 parents 5dd3b4b + f921edf commit 212fc67

File tree

24 files changed

+400
-360
lines changed

24 files changed

+400
-360
lines changed

pyobs_archive/api/apps.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,4 @@
22

33

44
class QueryConfig(AppConfig):
5-
name = 'pyobs_archive.archive'
5+
name = 'pyobs_archive.api'

pyobs_archive/api/models.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ def get_info(self):
140140
info['related_frames'] = [f.id for f in self.related.all()]
141141

142142
# add url
143-
info['url'] = urljoin(settings.ROOT_URL, 'frames/%d/download/' % self.id)
143+
info['url'] = 'frames/%d/download/' % self.id
144144

145145
# finished
146146
return info

pyobs_archive/api/views.py

Lines changed: 10 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,7 @@
1111
from astropy.io import fits
1212
from django.conf import settings
1313
from django.db.models import F
14-
from rest_framework import exceptions
15-
from rest_framework.decorators import permission_classes, authentication_classes, api_view
16-
from rest_framework.authentication import TokenAuthentication
14+
from rest_framework.decorators import permission_classes, api_view
1715
from rest_framework.permissions import IsAdminUser, IsAuthenticated
1816

1917
from pyobs_archive.api.models import Frame
@@ -22,23 +20,6 @@
2220
log = logging.getLogger(__name__)
2321

2422

25-
# define classes for authentication
26-
if settings.TOKEN_AUTH is None:
27-
AUTH_CLASSES = []
28-
POST_AUTH_CLASSES = []
29-
AUTHENTICATED = []
30-
else:
31-
class PostAuthentication(settings.TOKEN_AUTH):
32-
def authenticate(self, request):
33-
if 'auth_token' not in request.POST:
34-
raise exceptions.AuthenticationFailed('Missing token.')
35-
token = request.POST['auth_token']
36-
return self.authenticate_credentials(token)
37-
AUTH_CLASSES = [settings.TOKEN_AUTH]
38-
POST_AUTH_CLASSES = [PostAuthentication]
39-
AUTHENTICATED = [IsAuthenticated]
40-
41-
4223
def _frame(frame_id):
4324
# get frame
4425
try:
@@ -55,7 +36,6 @@ def _frame(frame_id):
5536

5637

5738
@api_view(['POST'])
58-
@authentication_classes(AUTH_CLASSES)
5939
@permission_classes([IsAdminUser])
6040
def create_view(request):
6141
# loop all incoming files
@@ -78,7 +58,6 @@ def create_view(request):
7858

7959

8060
@api_view(['GET'])
81-
@authentication_classes(AUTH_CLASSES)
8261
@permission_classes([IsAdminUser])
8362
def delete_view(request, frame_id):
8463
# get frame and filename
@@ -165,8 +144,7 @@ def filter_frames(data, request):
165144

166145

167146
@api_view(['GET'])
168-
@authentication_classes(AUTH_CLASSES)
169-
@permission_classes(AUTHENTICATED)
147+
@permission_classes([IsAuthenticated])
170148
def frames_view(request):
171149
# get offset and limit
172150
offset = request.GET.get('offset', default=None)
@@ -195,8 +173,7 @@ def frames_view(request):
195173

196174

197175
@api_view(['GET'])
198-
@authentication_classes(AUTH_CLASSES)
199-
@permission_classes(AUTHENTICATED)
176+
@permission_classes([IsAuthenticated])
200177
def aggregate_view(request):
201178
# get response
202179
data = Frame.objects
@@ -227,17 +204,15 @@ def aggregate_view(request):
227204

228205

229206
@api_view(['GET'])
230-
@authentication_classes(AUTH_CLASSES)
231-
@permission_classes(AUTHENTICATED)
207+
@permission_classes([IsAuthenticated])
232208
def frame_view(request, frame_id):
233209
# get data
234210
frame, filename = _frame(frame_id)
235211
return JsonResponse(frame.get_info())
236212

237213

238214
@api_view(['GET'])
239-
@authentication_classes(AUTH_CLASSES)
240-
@permission_classes(AUTHENTICATED)
215+
@permission_classes([IsAuthenticated])
241216
def download_view(request, frame_id):
242217
# get frame and filename
243218
frame, filename = _frame(frame_id)
@@ -251,8 +226,7 @@ def download_view(request, frame_id):
251226

252227

253228
@api_view(['GET'])
254-
@authentication_classes(AUTH_CLASSES)
255-
@permission_classes(AUTHENTICATED)
229+
@permission_classes([IsAuthenticated])
256230
def related_view(request, frame_id):
257231
# get frame
258232
frame, filename = _frame(frame_id)
@@ -263,8 +237,7 @@ def related_view(request, frame_id):
263237

264238

265239
@api_view(['GET'])
266-
@authentication_classes(AUTH_CLASSES)
267-
@permission_classes(AUTHENTICATED)
240+
@permission_classes([IsAuthenticated])
268241
def headers_view(request, frame_id):
269242
# get frame and filename
270243
frame, filename = _frame(frame_id)
@@ -278,6 +251,7 @@ def headers_view(request, frame_id):
278251

279252

280253
@api_view(['GET'])
254+
@permission_classes([IsAuthenticated])
281255
def preview_view(request, frame_id):
282256
import matplotlib
283257
matplotlib.use('Agg')
@@ -317,8 +291,7 @@ def preview_view(request, frame_id):
317291

318292

319293
@api_view(['POST'])
320-
@authentication_classes(POST_AUTH_CLASSES)
321-
@permission_classes(AUTHENTICATED)
294+
@permission_classes([IsAuthenticated])
322295
def zip_view(request):
323296
# get archive root
324297
root = settings.ARCHIVE_ROOT
@@ -345,8 +318,7 @@ def zip_view(request):
345318

346319

347320
@api_view(['GET'])
348-
@authentication_classes(AUTH_CLASSES)
349-
@permission_classes(AUTHENTICATED)
321+
@permission_classes([IsAuthenticated])
350322
def catalog_view(request, frame_id):
351323
# get frame and filename
352324
frame, filename = _frame(frame_id)
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
from django.contrib import admin
2+
3+
# Register your models here.
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
from django.apps import AppConfig
2+
3+
4+
class AuthenticationConfig(AppConfig):
5+
name = 'pyobs_archive.authentication'

pyobs_archive/authentication/authentication.py

Lines changed: 0 additions & 60 deletions
This file was deleted.
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
from django.contrib.auth.models import User
2+
from pyobs_archive.authentication.models import Profile
3+
from django.conf import settings
4+
from rest_framework import authentication, exceptions
5+
import requests
6+
7+
8+
class OAuth2Backend(object):
9+
"""
10+
Authenticate against the Oauth backend, using
11+
grant_type: password
12+
"""
13+
14+
def authenticate(self, request, username=None, password=None):
15+
if username == 'eng':
16+
return None # disable eng account
17+
response = requests.post(
18+
settings.OAUTH_CLIENT['TOKEN_URL'],
19+
data={
20+
'grant_type': 'password',
21+
'username': username,
22+
'password': password,
23+
'client_id': settings.OAUTH_CLIENT['CLIENT_ID'],
24+
'client_secret': settings.OAUTH_CLIENT['CLIENT_SECRET']
25+
}
26+
)
27+
if response.status_code == 200:
28+
user, _ = User.objects.get_or_create(username=username)
29+
Profile.objects.update_or_create(
30+
user=user,
31+
defaults={
32+
'access_token': response.json()['access_token'],
33+
'refresh_token': response.json()['refresh_token']
34+
}
35+
)
36+
return user
37+
return None
38+
39+
def get_user(self, user_id):
40+
try:
41+
return User.objects.get(pk=user_id)
42+
except User.DoesNotExist:
43+
return None
44+
45+
46+
class BearerAuthentication(authentication.BaseAuthentication):
47+
"""
48+
Allows users to authenticate using the bearer token recieved from
49+
the odin auth server
50+
"""
51+
def authenticate(self, request):
52+
auth_header = request.META.get('HTTP_AUTHORIZATION', '')
53+
if 'Bearer' not in auth_header:
54+
return None
55+
56+
bearer = auth_header.split('Bearer')[1].strip()
57+
response = requests.get(
58+
settings.OAUTH_CLIENT['PROFILE_URL'],
59+
headers={'Authorization': 'Bearer {}'.format(bearer)}
60+
)
61+
62+
if not response.status_code == 200:
63+
raise exceptions.AuthenticationFailed('No Such User')
64+
65+
user, _ = User.objects.get_or_create(username=response.json()['email'])
66+
Profile.objects.update_or_create(
67+
user=user,
68+
defaults={
69+
'access_token': bearer,
70+
}
71+
)
72+
return (user, None)
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# Generated by Django 3.2.4 on 2021-06-16 09:37
2+
3+
from django.conf import settings
4+
from django.db import migrations, models
5+
import django.db.models.deletion
6+
7+
8+
class Migration(migrations.Migration):
9+
10+
initial = True
11+
12+
dependencies = [
13+
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
14+
]
15+
16+
operations = [
17+
migrations.CreateModel(
18+
name='Profile',
19+
fields=[
20+
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
21+
('access_token', models.CharField(default='', max_length=255)),
22+
('refresh_token', models.CharField(default='', max_length=255)),
23+
('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
24+
],
25+
),
26+
]

pyobs_archive/authentication/migrations/__init__.py

Whitespace-only changes.
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
from django.db import models
2+
from django.contrib.auth.models import User
3+
from django.conf import settings
4+
from django.db.models.signals import post_save
5+
from django.dispatch import receiver
6+
from rest_framework.authtoken.models import Token
7+
import logging
8+
9+
logger = logging.getLogger()
10+
11+
12+
class Profile(models.Model):
13+
user = models.OneToOneField(User, on_delete=models.CASCADE)
14+
access_token = models.CharField(max_length=255, default='')
15+
refresh_token = models.CharField(max_length=255, default='')
16+
17+
18+
@receiver(post_save, sender=settings.AUTH_USER_MODEL)
19+
def create_auth_token(sender, instance=None, created=False, **kwargs):
20+
if created:
21+
Token.objects.create(user=instance)

0 commit comments

Comments
 (0)