├── .gitignore ├── .pre-commit-config.yaml ├── README.md ├── deploy └── nginx+tornado+daphne+supervisor │ ├── TornadoServer.py │ ├── network_daphne.ini │ ├── network_tornado.ini │ └── nginx.conf ├── manage.py ├── messager ├── __init__.py ├── apps.py ├── consumers.py ├── migrations │ └── __init__.py ├── models.py ├── tests │ ├── __init__.py │ ├── test_models.py │ └── test_views.py ├── urls.py └── views.py ├── notifications ├── __init__.py ├── apps.py ├── consumers.py ├── migrations │ └── __init__.py ├── models.py ├── tests │ ├── __init__.py │ ├── test_models.py │ └── test_views.py ├── urls.py └── views.py ├── nt_account ├── __init__.py ├── admin.py ├── apps.py ├── migrations │ ├── 0001_initial.py │ └── __init__.py ├── models.py ├── permissions.py ├── serializers.py ├── tasks.py ├── tests.py ├── urls.py └── views.py ├── nt_app ├── __init__.py ├── admin.py ├── apps.py ├── cache.py ├── migrations │ ├── 0001_initial.py │ └── __init__.py ├── models.py ├── serializers.py ├── tests.py ├── urls.py ├── utils.py └── views.py ├── nt_core ├── __init__.py ├── admin.py ├── apps.py ├── auto_schema.py ├── exception_handle.py ├── exceptions.py ├── migrations │ └── __init__.py ├── models.py ├── pagination.py ├── sentry_test.py ├── tests.py ├── utils.py └── views.py ├── nt_resource ├── __init__.py ├── admin.py ├── apps.py ├── cat_resource_import.py ├── filters.py ├── jobs.py ├── migrations │ ├── 0001_initial.py │ ├── 0002_catnormalresource_click_num.py │ └── __init__.py ├── models.py ├── serializers.py ├── tasks.py ├── tests.py ├── urls.py ├── utils.py └── views.py ├── nt_spark ├── __init__.py ├── admin.py ├── apps.py ├── cache.py ├── migrations │ ├── 0001_initial.py │ └── __init__.py ├── models.py ├── serializers.py ├── spark_sql_base.py ├── tests.py ├── urls.py ├── utils.py └── views.py ├── nt_user ├── __init__.py ├── admin.py ├── apps.py ├── migrations │ ├── 0001_initial.py │ ├── 0002_userfeedbackmessage.py │ └── __init__.py ├── models.py ├── serializers.py ├── signals.py ├── tests.py ├── urls.py └── views.py ├── requirements.txt ├── search ├── __init__.py ├── apps.py ├── search.html └── search_indexes.py ├── social_core ├── __init__.py ├── actions.py ├── backends │ ├── __init__.py │ ├── amazon.py │ ├── angel.py │ ├── aol.py │ ├── appsfuel.py │ ├── arcgis.py │ ├── asana.py │ ├── atlassian.py │ ├── azuread.py │ ├── azuread_b2c.py │ ├── azuread_tenant.py │ ├── base.py │ ├── battlenet.py │ ├── beats.py │ ├── behance.py │ ├── belgiumeid.py │ ├── bitbucket.py │ ├── box.py │ ├── bungie.py │ ├── changetip.py │ ├── chatwork.py │ ├── classlink.py │ ├── clef.py │ ├── coding.py │ ├── coinbase.py │ ├── coursera.py │ ├── dailymotion.py │ ├── deezer.py │ ├── digitalocean.py │ ├── discord.py │ ├── disqus.py │ ├── docker.py │ ├── douban.py │ ├── dribbble.py │ ├── drip.py │ ├── dropbox.py │ ├── echosign.py │ ├── edmodo.py │ ├── elixir.py │ ├── email.py │ ├── eventbrite.py │ ├── eveonline.py │ ├── evernote.py │ ├── exacttarget.py │ ├── facebook.py │ ├── fedora.py │ ├── fitbit.py │ ├── five_hundred_px.py │ ├── flat.py │ ├── flickr.py │ ├── foursquare.py │ ├── gae.py │ ├── github.py │ ├── github_enterprise.py │ ├── gitlab.py │ ├── globus.py │ ├── goclio.py │ ├── goclioeu.py │ ├── google.py │ ├── google_openidconnect.py │ ├── instagram.py │ ├── itembase.py │ ├── jawbone.py │ ├── justgiving.py │ ├── kakao.py │ ├── keycloak.py │ ├── khanacademy.py │ ├── lastfm.py │ ├── launchpad.py │ ├── legacy.py │ ├── line.py │ ├── linkedin.py │ ├── live.py │ ├── livejournal.py │ ├── loginradius.py │ ├── lyft.py │ ├── mailchimp.py │ ├── mailru.py │ ├── mapmyfitness.py │ ├── mediawiki.py │ ├── meetup.py │ ├── mendeley.py │ ├── microsoft.py │ ├── mineid.py │ ├── mixcloud.py │ ├── monzo.py │ ├── moves.py │ ├── nationbuilder.py │ ├── naver.py │ ├── ngpvan.py │ ├── nk.py │ ├── oauth.py │ ├── odnoklassniki.py │ ├── open_id.py │ ├── open_id_connect.py │ ├── openshift.py │ ├── openstreetmap.py │ ├── orbi.py │ ├── orcid.py │ ├── patreon.py │ ├── persona.py │ ├── phabricator.py │ ├── pinterest.py │ ├── pixelpin.py │ ├── pocket.py │ ├── podio.py │ ├── professionali.py │ ├── pushbullet.py │ ├── qiita.py │ ├── qq.py │ ├── quizlet.py │ ├── rdio.py │ ├── readability.py │ ├── reddit.py │ ├── runkeeper.py │ ├── salesforce.py │ ├── saml.py │ ├── scistarter.py │ ├── shimmering.py │ ├── shopify.py │ ├── sketchfab.py │ ├── skyrock.py │ ├── slack.py │ ├── soundcloud.py │ ├── spotify.py │ ├── stackoverflow.py │ ├── steam.py │ ├── stocktwits.py │ ├── strava.py │ ├── stripe.py │ ├── suse.py │ ├── taobao.py │ ├── telegram.py │ ├── thisismyjam.py │ ├── trello.py │ ├── tripit.py │ ├── tumblr.py │ ├── twilio.py │ ├── twitch.py │ ├── twitter.py │ ├── uber.py │ ├── ubuntu.py │ ├── udata.py │ ├── untappd.py │ ├── upwork.py │ ├── username.py │ ├── utils.py │ ├── vend.py │ ├── vimeo.py │ ├── vk.py │ ├── weibo.py │ ├── weixin.py │ ├── withings.py │ ├── wunderlist.py │ ├── xing.py │ ├── yahoo.py │ ├── yammer.py │ ├── yandex.py │ └── zotero.py ├── exceptions.py ├── pipeline │ ├── __init__.py │ ├── debug.py │ ├── disconnect.py │ ├── mail.py │ ├── partial.py │ ├── social_auth.py │ ├── user.py │ └── utils.py ├── storage.py ├── store.py ├── strategy.py ├── tests │ ├── __init__.py │ ├── actions │ │ ├── __init__.py │ │ ├── actions.py │ │ ├── test_associate.py │ │ ├── test_disconnect.py │ │ └── test_login.py │ ├── backends │ │ ├── __init__.py │ │ ├── base.py │ │ ├── legacy.py │ │ ├── oauth.py │ │ ├── open_id.py │ │ ├── open_id_connect.py │ │ ├── test_amazon.py │ │ ├── test_angel.py │ │ ├── test_arcgis.py │ │ ├── test_asana.py │ │ ├── test_atlassian.py │ │ ├── test_azuread.py │ │ ├── test_azuread_b2c.py │ │ ├── test_behance.py │ │ ├── test_bitbucket.py │ │ ├── test_box.py │ │ ├── test_broken.py │ │ ├── test_chatwork.py │ │ ├── test_clef.py │ │ ├── test_coinbase.py │ │ ├── test_coursera.py │ │ ├── test_dailymotion.py │ │ ├── test_deezer.py │ │ ├── test_digitalocean.py │ │ ├── test_disqus.py │ │ ├── test_dribbble.py │ │ ├── test_drip.py │ │ ├── test_dropbox.py │ │ ├── test_dummy.py │ │ ├── test_edmodo.py │ │ ├── test_elixir.py │ │ ├── test_email.py │ │ ├── test_eventbrite.py │ │ ├── test_evernote.py │ │ ├── test_facebook.py │ │ ├── test_fitbit.py │ │ ├── test_five_hundred_px.py │ │ ├── test_flat.py │ │ ├── test_flickr.py │ │ ├── test_foursquare.py │ │ ├── test_github.py │ │ ├── test_github_enterprise.py │ │ ├── test_gitlab.py │ │ ├── test_globus.py │ │ ├── test_google.py │ │ ├── test_instagram.py │ │ ├── test_itembase.py │ │ ├── test_kakao.py │ │ ├── test_keycloak.py │ │ ├── test_khanacademy.py │ │ ├── test_linkedin.py │ │ ├── test_live.py │ │ ├── test_livejournal.py │ │ ├── test_lyft.py │ │ ├── test_mapmyfitness.py │ │ ├── test_mineid.py │ │ ├── test_mixcloud.py │ │ ├── test_nationbuilder.py │ │ ├── test_naver.py │ │ ├── test_ngpvan.py │ │ ├── test_orbi.py │ │ ├── test_patreon.py │ │ ├── test_phabricator.py │ │ ├── test_pinterest.py │ │ ├── test_podio.py │ │ ├── test_qiita.py │ │ ├── test_quizlet.py │ │ ├── test_readability.py │ │ ├── test_reddit.py │ │ ├── test_saml.py │ │ ├── test_scistarter.py │ │ ├── test_sketchfab.py │ │ ├── test_skyrock.py │ │ ├── test_slack.py │ │ ├── test_soundcloud.py │ │ ├── test_spotify.py │ │ ├── test_stackoverflow.py │ │ ├── test_steam.py │ │ ├── test_stocktwits.py │ │ ├── test_strava.py │ │ ├── test_stripe.py │ │ ├── test_taobao.py │ │ ├── test_thisismyjam.py │ │ ├── test_tripit.py │ │ ├── test_tumblr.py │ │ ├── test_twitch.py │ │ ├── test_twitter.py │ │ ├── test_uber.py │ │ ├── test_udata.py │ │ ├── test_upwork.py │ │ ├── test_username.py │ │ ├── test_utils.py │ │ ├── test_vk.py │ │ ├── test_wunderlist.py │ │ ├── test_xing.py │ │ ├── test_yahoo.py │ │ ├── test_yammer.py │ │ ├── test_yandex.py │ │ └── test_zotero.py │ ├── models.py │ ├── pipeline.py │ ├── strategy.py │ ├── test_exceptions.py │ ├── test_partial.py │ ├── test_pipeline.py │ ├── test_storage.py │ └── test_utils.py └── utils.py ├── templates └── search │ └── users_text.txt └── web ├── .gitignore ├── __init__.py ├── asgi.py ├── celery.py ├── routing.py ├── settings.py ├── settings_local.py.example ├── urls.py ├── urls_api_v1.py └── wsgi.py /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | - repo: https://github.com/pre-commit/pre-commit-hooks 2 | sha: v1.11.1 3 | hooks: 4 | - id: trailing-whitespace 5 | - id: end-of-file-fixer 6 | - id: check-json 7 | - id: flake8 8 | exclude: migrations|.*\_local.py|manage.py|settings.py 9 | -------------------------------------------------------------------------------- /deploy/nginx+tornado+daphne+supervisor/TornadoServer.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | # -*- coding:utf-8 -*- 3 | 4 | import os 5 | import sys 6 | from tornado.options import options, define 7 | from django.core.wsgi import get_wsgi_application 8 | import tornado.httpserver 9 | import tornado.ioloop 10 | import tornado.web 11 | import tornado.wsgi 12 | 13 | # Django Application加入查找路径中 14 | app_path = os.path.abspath(os.path.join(os.path.dirname(os.path.abspath(__file__)), os.pardir)) 15 | define("port", default=6000, type=int, help="run on the given port") 16 | 17 | 18 | def main(): 19 | tornado.options.parse_command_line() 20 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "web.settings_local") 21 | wsgi_app = tornado.wsgi.WSGIContainer(get_wsgi_application()) 22 | http_server = tornado.httpserver.HTTPServer(wsgi_app, xheaders=True) # xheaders=True是啥意思? 23 | http_server.listen(options.port) 24 | tornado.ioloop.IOLoop.instance().start() 25 | 26 | 27 | if __name__ == "__main__": 28 | main() 29 | -------------------------------------------------------------------------------- /deploy/nginx+tornado+daphne+supervisor/network_daphne.ini: -------------------------------------------------------------------------------- 1 | [program:daphne] 2 | # 执行用户 3 | user = zanhu 4 | # 在该目录下执行下面command命令 5 | directory = /home/zanhu/zanhu 6 | # 执行的命令 7 | command = /usr/local/python3/bin/daphne -p 8000 config.asgi:application 8 | # 日志文件配置 9 | loglevel = info 10 | stdout_logfile = /home/zanhu/zanhu/logs/daphne.log 11 | stderr_logfile = /home/zanhu/zanhu/logs/daphne_error.log 12 | stdout_logfile_maxbytes = 100MB 13 | stdout_logfile_backups = 3 14 | # 给每个进程命名,便于管理 15 | process_name = daphne_worker%(process_num)s 16 | # 启动的进程数,设置成云服务器的vCPU数 17 | numprocs_start = 1 18 | numprocs = 1 19 | max-requests = 5000 20 | # 设置自启和重启 21 | autostart = true 22 | autorestart = true 23 | redirect_stderr = True 24 | -------------------------------------------------------------------------------- /deploy/nginx+tornado+daphne+supervisor/network_tornado.ini: -------------------------------------------------------------------------------- 1 | [program:tornado] 2 | # 在该目录下执行下面command命令 3 | directory = /home/network_anomaly_detection/ 4 | # 执行的命令 python3 TornadoServer.py --port=6001 5 | command = python3 /home/network_anomaly_detection/deploy/nginx+tornado+daphne+supervisor/TornadoServer.py --port=60%(process_num)02d 6 | # 日志文件配置 7 | loglevel = info 8 | stdout_logfile = /home/network_anomaly_detection/logs/tornado.log 9 | stderr_logfile = /home/network_anomaly_detection/logs/tornado_error.log 10 | stdout_logfile_maxbytes = 100MB 11 | stdout_logfile_backups = 3 12 | # 给每个进程命名,便于管理 13 | process_name = tornado_worker%(process_num)s 14 | # 启动的进程数,设置成云服务器的vCPU数 15 | numprocs_start = 1 16 | numprocs = 4 17 | max-requests = 5000 18 | # 设置自启和重启 19 | autostart = true 20 | autorestart = true 21 | redirect_stderr = True 22 | -------------------------------------------------------------------------------- /manage.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import os 3 | import sys 4 | 5 | if __name__ == '__main__': 6 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'web.settings_local') 7 | try: 8 | from django.core.management import execute_from_command_line 9 | except ImportError as exc: 10 | raise ImportError( 11 | "Couldn't import Django. Are you sure it's installed and " 12 | "available on your PYTHONPATH environment variable? Did you " 13 | "forget to activate a virtual environment?" 14 | ) from exc 15 | execute_from_command_line(sys.argv) 16 | -------------------------------------------------------------------------------- /messager/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/harvardfly/network_anomaly_detection/88f37dc53defb6a424f7f3124ccabc31eb9c274e/messager/__init__.py -------------------------------------------------------------------------------- /messager/apps.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | # -*- coding:utf-8 -*- 3 | 4 | from django.apps import AppConfig 5 | 6 | 7 | class MessagerConfig(AppConfig): 8 | name = 'messager' 9 | verbose_name = '消息' 10 | -------------------------------------------------------------------------------- /messager/migrations/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/harvardfly/network_anomaly_detection/88f37dc53defb6a424f7f3124ccabc31eb9c274e/messager/migrations/__init__.py -------------------------------------------------------------------------------- /messager/tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/harvardfly/network_anomaly_detection/88f37dc53defb6a424f7f3124ccabc31eb9c274e/messager/tests/__init__.py -------------------------------------------------------------------------------- /messager/urls.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | # -*- coding:utf-8 -*- 3 | 4 | from django.urls import path 5 | 6 | from messager import views 7 | 8 | app_name = 'messager' 9 | 10 | urlpatterns = [ 11 | path('', views.MessagesListView.as_view(), name='messages_list'), 12 | path('send-message/', views.send_message, name='send_message'), 13 | path('/', views.ConversationListView.as_view(), name='conversation_detail'), 14 | ] 15 | -------------------------------------------------------------------------------- /notifications/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/harvardfly/network_anomaly_detection/88f37dc53defb6a424f7f3124ccabc31eb9c274e/notifications/__init__.py -------------------------------------------------------------------------------- /notifications/apps.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | # -*- coding:utf-8 -*- 3 | 4 | from django.apps import AppConfig 5 | 6 | 7 | class NotificationsConfig(AppConfig): 8 | name = 'notifications' 9 | verbose_name = '通知' 10 | -------------------------------------------------------------------------------- /notifications/consumers.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | # -*- coding:utf-8 -*- 3 | 4 | import json 5 | 6 | from channels.generic.websocket import AsyncWebsocketConsumer 7 | 8 | 9 | class NotificationsConsumer(AsyncWebsocketConsumer): 10 | """处理通知应用中的WebSocket请求""" 11 | 12 | async def connect(self): 13 | """建立连接""" 14 | if self.scope['user'].is_anonymous: 15 | # 未登录用户拒绝连接 16 | await self.close() 17 | else: 18 | await self.channel_layer.group_add('notifications', self.channel_name) 19 | await self.accept() 20 | 21 | async def receive(self, text_data=None, bytes_data=None): 22 | """将接收到的消息返回给前端""" 23 | await self.send(text_data=json.dumps(text_data)) 24 | 25 | async def disconnect(self, code): 26 | """断开连接""" 27 | await self.channel_layer.group_discard('notifications', self.channel_name) 28 | -------------------------------------------------------------------------------- /notifications/migrations/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/harvardfly/network_anomaly_detection/88f37dc53defb6a424f7f3124ccabc31eb9c274e/notifications/migrations/__init__.py -------------------------------------------------------------------------------- /notifications/tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/harvardfly/network_anomaly_detection/88f37dc53defb6a424f7f3124ccabc31eb9c274e/notifications/tests/__init__.py -------------------------------------------------------------------------------- /notifications/urls.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | # -*- coding:utf-8 -*- 3 | 4 | from django.urls import path 5 | 6 | from notifications import views 7 | 8 | app_name = 'notifications' 9 | 10 | urlpatterns = [ 11 | path('', views.NotificationUnreadListView.as_view(), name='unread'), 12 | path('mark-as-read//', views.mark_as_read, name='mark_as_read'), 13 | path('mark-all-as-read/', views.mark_all_as_read, name='mark_all_read'), 14 | path('latest-notifications/', views.get_latest_notifications, name='latest_notifications'), 15 | ] 16 | -------------------------------------------------------------------------------- /nt_account/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/harvardfly/network_anomaly_detection/88f37dc53defb6a424f7f3124ccabc31eb9c274e/nt_account/__init__.py -------------------------------------------------------------------------------- /nt_account/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | 3 | # Register your models here. 4 | -------------------------------------------------------------------------------- /nt_account/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class NtAccountConfig(AppConfig): 5 | name = 'nt_account' 6 | -------------------------------------------------------------------------------- /nt_account/migrations/0001_initial.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 2.1.2 on 2018-10-12 13:15 2 | 3 | from django.db import migrations, models 4 | import nt_core.models 5 | import uuid 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | initial = True 11 | 12 | dependencies = [ 13 | ] 14 | 15 | operations = [ 16 | migrations.CreateModel( 17 | name='UserApiRecordHistory', 18 | fields=[ 19 | ('id', models.CharField(default=uuid.uuid4, editable=False, max_length=40, primary_key=True, serialize=False)), 20 | ('create_time', models.BigIntegerField(default=nt_core.models.get_current_time_bigint)), 21 | ('update_time', models.BigIntegerField(default=nt_core.models.get_current_time_bigint)), 22 | ('user_id', models.IntegerField(blank=True, null=True)), 23 | ('app_url', models.CharField(blank=True, max_length=100, null=True)), 24 | ('path_info', models.CharField(blank=True, max_length=500, null=True)), 25 | ('query_string', models.CharField(blank=True, max_length=500, null=True)), 26 | ('post_data', models.CharField(blank=True, max_length=500, null=True)), 27 | ('remote_addr', models.GenericIPAddressField(blank=True, null=True)), 28 | ('method', models.CharField(blank=True, max_length=20, null=True)), 29 | ], 30 | options={ 31 | 'db_table': 'api_record_history', 32 | }, 33 | ), 34 | ] 35 | -------------------------------------------------------------------------------- /nt_account/migrations/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/harvardfly/network_anomaly_detection/88f37dc53defb6a424f7f3124ccabc31eb9c274e/nt_account/migrations/__init__.py -------------------------------------------------------------------------------- /nt_account/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | from nt_core.models import BaseModel 3 | 4 | 5 | class UserApiRecordHistory(BaseModel): 6 | user_id = models.IntegerField(blank=True, null=True) 7 | app_url = models.CharField(max_length=100, blank=True, null=True) 8 | path_info = models.CharField(max_length=500, blank=True, null=True) 9 | query_string = models.CharField(max_length=500, blank=True, null=True) 10 | post_data = models.CharField(max_length=500, blank=True, null=True) 11 | remote_addr = models.GenericIPAddressField(blank=True, null=True) 12 | method = models.CharField(max_length=20, blank=True, null=True) 13 | 14 | class Meta: 15 | db_table = 'api_record_history' 16 | -------------------------------------------------------------------------------- /nt_account/permissions.py: -------------------------------------------------------------------------------- 1 | from rest_framework import permissions 2 | 3 | 4 | class IsOwnerOrReadOnly(permissions.BasePermission): 5 | """ 6 | Object-level permission to only allow owners of an object to edit it. 7 | Assumes the model instance has an `owner` attribute. 8 | """ 9 | 10 | def has_object_permission(self, request, view, obj): 11 | # Read permissions are allowed to any request, 12 | # so we'll always allow GET, HEAD or OPTIONS requests. 13 | if request.method in permissions.SAFE_METHODS: 14 | return True 15 | 16 | # Instance must have an attribute named `owner`. 17 | return obj.user == request.user 18 | -------------------------------------------------------------------------------- /nt_account/serializers.py: -------------------------------------------------------------------------------- 1 | from rest_framework import serializers 2 | from nt_account.models import UserApiRecordHistory 3 | 4 | 5 | class UserApiRecordHistorySer(serializers.ModelSerializer): 6 | class Meta: 7 | model = UserApiRecordHistory 8 | fields = '__all__' 9 | -------------------------------------------------------------------------------- /nt_account/tasks.py: -------------------------------------------------------------------------------- 1 | from web.celery import app as celery_app 2 | from nt_account.models import UserApiRecordHistory 3 | 4 | 5 | @celery_app.task 6 | def save_api_record_task(data): 7 | """ 8 | 保存用户使用的接口记录 9 | :param data: 10 | :return: 11 | """ 12 | 13 | api_history = UserApiRecordHistory(**data) 14 | api_history.save() 15 | -------------------------------------------------------------------------------- /nt_account/tests.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | 3 | # Create your tests here. 4 | -------------------------------------------------------------------------------- /nt_account/urls.py: -------------------------------------------------------------------------------- 1 | from django.conf.urls import url 2 | 3 | from nt_account.views import ( 4 | GenerateTokenView 5 | ) 6 | 7 | urlpatterns = [ 8 | # search question 9 | url(r'^generate_token$', 10 | GenerateTokenView.as_view()), 11 | ] 12 | -------------------------------------------------------------------------------- /nt_app/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/harvardfly/network_anomaly_detection/88f37dc53defb6a424f7f3124ccabc31eb9c274e/nt_app/__init__.py -------------------------------------------------------------------------------- /nt_app/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | 3 | # Register your models here. 4 | -------------------------------------------------------------------------------- /nt_app/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class NtAppConfig(AppConfig): 5 | name = 'nt_app' 6 | -------------------------------------------------------------------------------- /nt_app/cache.py: -------------------------------------------------------------------------------- 1 | # coding:utf-8 2 | import time 3 | from django.core.cache import cache 4 | from nt_app.utils import get_cat_res_data 5 | 6 | 7 | CACHE_TIMEOUT_DEFAULT = 7 * 24 * 60 * 60 8 | 9 | 10 | def get_cache_cat_data(start_time, end_time, force=False): 11 | """ 12 | 获取指定时间段的cat数据 13 | :param start_time: 14 | :param end_time: 15 | :return: 16 | """ 17 | key = 'GET_CAT_RES_DATA_{0}_TO_{1}'.format( 18 | start_time, end_time 19 | ) 20 | content = cache.get(key) 21 | if force or not content: 22 | content = get_cat_res_data(start_time, end_time) 23 | if content: 24 | cache.set(key, content, timeout=CACHE_TIMEOUT_DEFAULT) 25 | 26 | return content 27 | -------------------------------------------------------------------------------- /nt_app/migrations/0001_initial.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 2.1.2 on 2018-10-12 14:36 2 | 3 | from django.db import migrations, models 4 | import nt_core.models 5 | import uuid 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | initial = True 11 | 12 | dependencies = [ 13 | ] 14 | 15 | operations = [ 16 | migrations.CreateModel( 17 | name='CatResource', 18 | fields=[ 19 | ('id', models.CharField(default=uuid.uuid4, editable=False, max_length=40, primary_key=True, serialize=False)), 20 | ('create_time', models.BigIntegerField(default=nt_core.models.get_current_time_bigint)), 21 | ('update_time', models.BigIntegerField(default=nt_core.models.get_current_time_bigint)), 22 | ('appid', models.IntegerField(blank=True, null=True)), 23 | ('response_time', models.FloatField(blank=True, null=True)), 24 | ('request_count', models.IntegerField(blank=True, null=True)), 25 | ('fail_count', models.IntegerField(blank=True, null=True)), 26 | ], 27 | options={ 28 | 'db_table': 'cat_resource', 29 | }, 30 | ), 31 | ] 32 | -------------------------------------------------------------------------------- /nt_app/migrations/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/harvardfly/network_anomaly_detection/88f37dc53defb6a424f7f3124ccabc31eb9c274e/nt_app/migrations/__init__.py -------------------------------------------------------------------------------- /nt_app/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | from nt_core.models import BaseModel 3 | 4 | 5 | class CatResource(BaseModel): 6 | # 全量数据 7 | appid = models.IntegerField(blank=True, null=True) 8 | response_time = models.FloatField(blank=True, null=True) 9 | request_count = models.IntegerField(blank=True, null=True) 10 | fail_count = models.IntegerField(blank=True, null=True) 11 | 12 | class Meta: 13 | db_table = 'cat_resource' -------------------------------------------------------------------------------- /nt_app/serializers.py: -------------------------------------------------------------------------------- 1 | from rest_framework import serializers 2 | from nt_app.models import CatResource 3 | from nt_core.exceptions import RsError 4 | from nt_core.utils import get_current_timestamp 5 | 6 | 7 | class CatResourceListSerializer(serializers.ModelSerializer): 8 | class Meta: 9 | model = CatResource 10 | fields = '__all__' 11 | 12 | def update(self, instance, validated_data): 13 | instance.appid = validated_data.get('appid', instance.appid) 14 | instance.response_time = validated_data.get( 15 | 'response_time', instance.response_time 16 | ) 17 | 18 | instance.update_time = get_current_timestamp() 19 | instance.save() 20 | return instance 21 | 22 | 23 | class CatResourceCreateSerializer(serializers.Serializer): 24 | appid = serializers.IntegerField(required=True) 25 | response_time = serializers.FloatField(required=True) 26 | request_count = serializers.IntegerField(required=True) 27 | fail_count = serializers.IntegerField(required=True) 28 | 29 | def validate(self, attrs): 30 | request_count = attrs.get('request_count') 31 | fail_count = attrs.get('fail_count') 32 | if fail_count > request_count: 33 | raise RsError("失败次数不能大于请求数") 34 | 35 | return attrs 36 | -------------------------------------------------------------------------------- /nt_app/tests.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | 3 | # Create your tests here. 4 | -------------------------------------------------------------------------------- /nt_app/urls.py: -------------------------------------------------------------------------------- 1 | from django.conf.urls import url 2 | from nt_app.views import ( 3 | CatResourceView, 4 | CatResourceListView 5 | ) 6 | 7 | urlpatterns = [ 8 | url(r'^cat_resource$', CatResourceView.as_view()), 9 | url(r'^cat_list$', CatResourceListView.as_view()), 10 | ] 11 | -------------------------------------------------------------------------------- /nt_app/utils.py: -------------------------------------------------------------------------------- 1 | from nt_app.models import CatResource 2 | from nt_app.serializers import CatResourceListSerializer 3 | 4 | 5 | def get_cat_res_data(start_time, end_time): 6 | """ 7 | 获取特定时间段的cat数据 8 | :param start_time: 9 | :param end_time: 10 | :return: 11 | """ 12 | cat_objs = CatResource.objects.filter( 13 | create_time__gt=start_time, 14 | update_time__lt=end_time 15 | ).all() 16 | ser_data = CatResourceListSerializer(cat_objs, many=True).data 17 | return ser_data 18 | -------------------------------------------------------------------------------- /nt_core/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/harvardfly/network_anomaly_detection/88f37dc53defb6a424f7f3124ccabc31eb9c274e/nt_core/__init__.py -------------------------------------------------------------------------------- /nt_core/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | 3 | # Register your models here. 4 | -------------------------------------------------------------------------------- /nt_core/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class NtCoreConfig(AppConfig): 5 | name = 'nt_core' 6 | -------------------------------------------------------------------------------- /nt_core/exception_handle.py: -------------------------------------------------------------------------------- 1 | from rest_framework.views import exception_handler 2 | from django.http.response import Http404 3 | 4 | 5 | def rs_exception_handler(exc, context): 6 | # Call REST framework's default exception handler first, 7 | # to get the standard error response. 8 | response = exception_handler(exc, context) 9 | 10 | # Now add the HTTP status code to the response. 11 | if response is not None: 12 | response.data['error'] = 1 13 | 14 | if isinstance(exc, Http404): 15 | response.data['detail'] = '404错误出现,请仔细检查。' 16 | 17 | return response 18 | -------------------------------------------------------------------------------- /nt_core/exceptions.py: -------------------------------------------------------------------------------- 1 | from rest_framework.exceptions import APIException 2 | from rest_framework import status 3 | 4 | 5 | class RsError(APIException): 6 | """ 7 | 自定义Exception 8 | """ 9 | status_code = status.HTTP_200_OK 10 | default_detail = '未知错误,请联系管理员.' 11 | 12 | def __init__(self, detail=None, code=None): 13 | if detail is None: 14 | detail = self.default_detail 15 | 16 | self.detail = detail 17 | 18 | def __str__(self): 19 | return self.detail 20 | -------------------------------------------------------------------------------- /nt_core/migrations/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/harvardfly/network_anomaly_detection/88f37dc53defb6a424f7f3124ccabc31eb9c274e/nt_core/migrations/__init__.py -------------------------------------------------------------------------------- /nt_core/models.py: -------------------------------------------------------------------------------- 1 | import time 2 | from uuid import uuid4 3 | from django.db import models 4 | 5 | 6 | def get_current_time_bigint(): 7 | return int(time.time()) * 1000 8 | 9 | 10 | class BaseModel(models.Model): 11 | id = models.CharField( 12 | primary_key=True, max_length=40, default=uuid4, editable=False 13 | ) 14 | create_time = models.BigIntegerField(default=get_current_time_bigint) 15 | update_time = models.BigIntegerField(default=get_current_time_bigint) 16 | 17 | def save(self, *args, **kwargs): 18 | self.update_time = get_current_time_bigint() 19 | super(BaseModel, self).save(*args, **kwargs) 20 | 21 | class Meta: 22 | abstract = True 23 | -------------------------------------------------------------------------------- /nt_core/sentry_test.py: -------------------------------------------------------------------------------- 1 | from raven import Client 2 | 3 | dsn = "" 4 | client = Client(dsn) 5 | 6 | try: 7 | 1 / 0 8 | except ZeroDivisionError: 9 | client.captureException() 10 | -------------------------------------------------------------------------------- /nt_core/tests.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | 3 | # Create your tests here. 4 | -------------------------------------------------------------------------------- /nt_core/views.py: -------------------------------------------------------------------------------- 1 | from django.shortcuts import render 2 | 3 | # Create your views here. 4 | -------------------------------------------------------------------------------- /nt_resource/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/harvardfly/network_anomaly_detection/88f37dc53defb6a424f7f3124ccabc31eb9c274e/nt_resource/__init__.py -------------------------------------------------------------------------------- /nt_resource/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | 3 | # Register your models here. 4 | -------------------------------------------------------------------------------- /nt_resource/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class NtResourceConfig(AppConfig): 5 | name = 'nt_resource' 6 | -------------------------------------------------------------------------------- /nt_resource/cat_resource_import.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import os 3 | import sys 4 | from django.core.wsgi import get_wsgi_application 5 | 6 | local_path = sys.path[0] 7 | sys.path.append(os.path.join(local_path, '../')) # NoQA 8 | os.environ['DJANGO_SETTINGS_MODULE'] = 'web.settings_local' 9 | application = get_wsgi_application() 10 | 11 | from nt_resource.tasks import insert_cat_data # NoQA 12 | 13 | insert_cat_data.delay(1538331058000, 1539934343000) 14 | -------------------------------------------------------------------------------- /nt_resource/filters.py: -------------------------------------------------------------------------------- 1 | import django_filters 2 | from django.db.models import Q 3 | 4 | from nt_resource.models import CatNormalResource 5 | 6 | 7 | class CatNormalResourceFilter(django_filters.rest_framework.FilterSet): 8 | """ 9 | 的过滤类 10 | """ 11 | min_count = django_filters.NumberFilter( 12 | field_name='fail_count', 13 | help_text="最小失败次数", 14 | lookup_expr='gte' 15 | ) 16 | 17 | max_count = django_filters.NumberFilter( 18 | field_name='fail_count', 19 | help_text="最大失败次数", 20 | lookup_expr='lte' 21 | ) 22 | normal_cat = django_filters.NumberFilter(method='normal_cat_filter') 23 | 24 | def normal_cat_filter(self, queryset, name, value): 25 | """ 26 | 定义异常指标 值可以是response_time、request_count或者fail_count 27 | :param queryset: 28 | :param name: 29 | :param value: 30 | :return: 31 | """ 32 | return queryset.filter( 33 | Q(response_time=value) | 34 | Q(request_count=value) | 35 | Q(fail_count=value) 36 | ) 37 | 38 | class Meta: 39 | model = CatNormalResource 40 | fields = [ 41 | "min_count", "max_count", 42 | "appid", "response_time", 43 | "request_count", "fail_count" 44 | ] 45 | -------------------------------------------------------------------------------- /nt_resource/jobs.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import logging 3 | import datetime 4 | 5 | from nt_app.cache import get_cache_cat_data 6 | from nt_resource.tasks import insert_normal_cat_data 7 | from nt_core.utils import ( 8 | get_current_timestamp, 9 | convert_datetime_to_timestamp 10 | ) 11 | 12 | logger = logging.getLogger(__name__) 13 | 14 | 15 | def my_scheduled_job(): 16 | logger.info('my_scheduled_job ....') 17 | 18 | 19 | def insert_normal_cat_job(): 20 | """ 21 | 定时导入前一天的正常数据 22 | :return: 23 | """ 24 | logger.info('insert_normal_cat_job ....') 25 | dt_time = datetime.datetime.now() + datetime.timedelta(days=-1) 26 | start_time = convert_datetime_to_timestamp(dt_time) 27 | end_time = get_current_timestamp() 28 | data = get_cache_cat_data(start_time, end_time) 29 | insert_normal_cat_data.delay(data) 30 | -------------------------------------------------------------------------------- /nt_resource/migrations/0001_initial.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 2.1.2 on 2018-10-13 16:32 2 | 3 | from django.db import migrations, models 4 | import nt_core.models 5 | import uuid 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | initial = True 11 | 12 | dependencies = [ 13 | ] 14 | 15 | operations = [ 16 | migrations.CreateModel( 17 | name='CatNormalResource', 18 | fields=[ 19 | ('id', models.CharField(default=uuid.uuid4, editable=False, max_length=40, primary_key=True, serialize=False)), 20 | ('create_time', models.BigIntegerField(default=nt_core.models.get_current_time_bigint)), 21 | ('update_time', models.BigIntegerField(default=nt_core.models.get_current_time_bigint)), 22 | ('appid', models.IntegerField(blank=True, null=True)), 23 | ('response_time', models.FloatField(blank=True, null=True)), 24 | ('request_count', models.IntegerField(blank=True, null=True)), 25 | ('fail_count', models.IntegerField(blank=True, null=True)), 26 | ], 27 | options={ 28 | 'db_table': 'cat_normal_resource', 29 | }, 30 | ), 31 | ] 32 | -------------------------------------------------------------------------------- /nt_resource/migrations/0002_catnormalresource_click_num.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 2.1.2 on 2018-12-10 21:42 2 | 3 | from django.db import migrations, models 4 | 5 | 6 | class Migration(migrations.Migration): 7 | 8 | dependencies = [ 9 | ('nt_resource', '0001_initial'), 10 | ] 11 | 12 | operations = [ 13 | migrations.AddField( 14 | model_name='catnormalresource', 15 | name='click_num', 16 | field=models.IntegerField(blank=True, default=0, null=True), 17 | ), 18 | ] 19 | -------------------------------------------------------------------------------- /nt_resource/migrations/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/harvardfly/network_anomaly_detection/88f37dc53defb6a424f7f3124ccabc31eb9c274e/nt_resource/migrations/__init__.py -------------------------------------------------------------------------------- /nt_resource/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | from nt_core.models import BaseModel 3 | 4 | 5 | class CatNormalResource(BaseModel): 6 | appid = models.IntegerField(blank=True, null=True) 7 | response_time = models.FloatField(blank=True, null=True) 8 | request_count = models.IntegerField(blank=True, null=True) 9 | fail_count = models.IntegerField(blank=True, null=True) 10 | click_num = models.IntegerField(blank=True, null=True, default=0) 11 | 12 | class Meta: 13 | db_table = 'cat_normal_resource' 14 | -------------------------------------------------------------------------------- /nt_resource/serializers.py: -------------------------------------------------------------------------------- 1 | from rest_framework import serializers 2 | from nt_resource.models import CatNormalResource 3 | from nt_core.utils import get_current_timestamp 4 | 5 | 6 | class CatNormalResourceListSerializer(serializers.ModelSerializer): 7 | class Meta: 8 | model = CatNormalResource 9 | fields = '__all__' 10 | 11 | def update(self, instance, validated_data): 12 | instance.appid = validated_data.get('appid', instance.appid) 13 | instance.response_time = validated_data.get( 14 | 'response_time', instance.response_time 15 | ) 16 | 17 | instance.update_time = get_current_timestamp() 18 | instance.save() 19 | return instance 20 | -------------------------------------------------------------------------------- /nt_resource/tasks.py: -------------------------------------------------------------------------------- 1 | from web.celery import app as celery_app 2 | from nt_core.exceptions import RsError 3 | from nt_resource.utils import ( 4 | add_cat_data, 5 | add_normal_cat_data 6 | ) 7 | from nt_resource.models import CatNormalResource 8 | 9 | 10 | @celery_app.task 11 | def insert_cat_data(start_time, end_time): 12 | """ 13 | 使用异步,批量插入指定时间段的cat数据 14 | :param start_time: 15 | :param end_time: 16 | :return: 17 | """ 18 | try: 19 | for i in add_cat_data(start_time, end_time): 20 | CatNormalResource.objects.bulk_create(i) 21 | except Exception as e: 22 | print(e) 23 | raise RsError('插入数据库失败') 24 | 25 | 26 | @celery_app.task 27 | def insert_normal_cat_data(data): 28 | """ 29 | 使用异步,每次用bulk 批量插入 1000条数据 30 | :param data: 31 | :return: 32 | """ 33 | try: 34 | for i in add_normal_cat_data(data): 35 | CatNormalResource.objects.bulk_create(i) 36 | except Exception as e: 37 | print(e) 38 | raise RsError('插入数据库失败') 39 | 40 | 41 | @celery_app.task(bind=True, default_retry_delay=60, max_retries=2) 42 | def insert_dt(self): 43 | print("----- not implemented ------") 44 | pass 45 | -------------------------------------------------------------------------------- /nt_resource/tests.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | 3 | # Create your tests here. 4 | -------------------------------------------------------------------------------- /nt_resource/urls.py: -------------------------------------------------------------------------------- 1 | from django.conf.urls import url 2 | from nt_resource.views import ( 3 | CatNormalResourceView, 4 | CatNormalResourceListView 5 | ) 6 | from rest_framework.routers import DefaultRouter 7 | 8 | router = DefaultRouter() 9 | 10 | router.register( 11 | r'^cat_normal_list', 12 | CatNormalResourceListView, 13 | base_name="cat_normal_list" 14 | ) 15 | 16 | urlpatterns = [ 17 | url(r'^cat_normal_resource$', CatNormalResourceView.as_view()), 18 | # url(r'^cat_normal_list$', cat_list), 19 | ] 20 | 21 | urlpatterns += router.urls 22 | -------------------------------------------------------------------------------- /nt_resource/utils.py: -------------------------------------------------------------------------------- 1 | from uuid import uuid4 2 | from nt_resource.models import CatNormalResource 3 | from nt_app.cache import get_cache_cat_data 4 | 5 | 6 | def add_normal_cat_data(data): 7 | """ 8 | 构建数据model 用yield每次返回1000条数据 9 | :param data 10 | :return: 11 | """ 12 | tmp_cat_normal_models = [] 13 | 14 | for cat_data in data: 15 | response_time = cat_data.get('response_time') 16 | request_count = cat_data.get('request_count') or 1 17 | fail_count = cat_data.get('fail_count') or 1 18 | cat_data['id'] = str(uuid4()) 19 | if response_time < 1.2 and (fail_count / request_count) < 0.2: 20 | cat_obj = CatNormalResource( 21 | **cat_data 22 | ) 23 | tmp_cat_normal_models.append(cat_obj) 24 | 25 | if len(tmp_cat_normal_models) >= 1000: 26 | yield tmp_cat_normal_models 27 | tmp_cat_normal_models = [] 28 | 29 | yield tmp_cat_normal_models 30 | 31 | 32 | def add_cat_data(start_time, end_time): 33 | """ 34 | 真实的正常数据、判断的异常可能是正常, 35 | 此时需人为主动插入数据 36 | :param start_time: 37 | :param end_time: 38 | :return: 39 | """ 40 | data = get_cache_cat_data(start_time, end_time) 41 | tmp_cat_normal_models = [] 42 | 43 | for cat_data in data: 44 | cat_data['id'] = str(uuid4()) 45 | cat_obj = CatNormalResource( 46 | **cat_data 47 | ) 48 | tmp_cat_normal_models.append(cat_obj) 49 | 50 | if len(tmp_cat_normal_models) >= 1000: 51 | yield tmp_cat_normal_models 52 | tmp_cat_normal_models = [] 53 | 54 | yield tmp_cat_normal_models 55 | -------------------------------------------------------------------------------- /nt_spark/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/harvardfly/network_anomaly_detection/88f37dc53defb6a424f7f3124ccabc31eb9c274e/nt_spark/__init__.py -------------------------------------------------------------------------------- /nt_spark/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | 3 | # Register your models here. 4 | -------------------------------------------------------------------------------- /nt_spark/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class NtSparkConfig(AppConfig): 5 | name = 'nt_spark' 6 | -------------------------------------------------------------------------------- /nt_spark/cache.py: -------------------------------------------------------------------------------- 1 | # coding:utf-8 2 | from django.core.cache import cache 3 | from nt_spark.utils import get_kmeans_result 4 | 5 | CACHE_TIMEOUT_DEFAULT = 7 * 24 * 60 * 60 6 | 7 | 8 | def get_cache_kmeans_result(appid, start_time, end_time, force=False): 9 | """ 10 | 获取appid指定时间段的cat数据 11 | :param appid: 12 | :param start_time: 13 | :param end_time: 14 | :param force: 15 | :return: 16 | """ 17 | key = 'GET_KMEANS_RESULT_{0}_FROM_{1}_TO_{2}'.format( 18 | appid, start_time, end_time 19 | ) 20 | content = cache.get(key) 21 | if force or not content: 22 | content = get_kmeans_result(appid, start_time, end_time) 23 | if content: 24 | cache.set(key, content, timeout=CACHE_TIMEOUT_DEFAULT) 25 | 26 | return content 27 | -------------------------------------------------------------------------------- /nt_spark/migrations/0001_initial.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 2.1.2 on 2018-10-13 18:14 2 | 3 | from django.db import migrations, models 4 | import jsonfield.fields 5 | import nt_core.models 6 | import uuid 7 | 8 | 9 | class Migration(migrations.Migration): 10 | 11 | initial = True 12 | 13 | dependencies = [ 14 | ] 15 | 16 | operations = [ 17 | migrations.CreateModel( 18 | name='CatResultData', 19 | fields=[ 20 | ('id', models.CharField(default=uuid.uuid4, editable=False, max_length=40, primary_key=True, serialize=False)), 21 | ('create_time', models.BigIntegerField(default=nt_core.models.get_current_time_bigint)), 22 | ('update_time', models.BigIntegerField(default=nt_core.models.get_current_time_bigint)), 23 | ('appid', models.IntegerField(blank=True, null=True)), 24 | ('algorithm_name', models.CharField(blank=True, max_length=50, null=True)), 25 | ('start_time', models.BigIntegerField()), 26 | ('end_time', models.BigIntegerField()), 27 | ('result_data', jsonfield.fields.JSONField(blank=True, null=True)), 28 | ], 29 | options={ 30 | 'db_table': 'cat_result_data', 31 | }, 32 | ), 33 | ] 34 | -------------------------------------------------------------------------------- /nt_spark/migrations/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/harvardfly/network_anomaly_detection/88f37dc53defb6a424f7f3124ccabc31eb9c274e/nt_spark/migrations/__init__.py -------------------------------------------------------------------------------- /nt_spark/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | from nt_core.models import BaseModel 3 | from jsonfield import JSONField 4 | 5 | 6 | class CatResultData(BaseModel): 7 | appid = models.IntegerField(blank=True, null=True) 8 | algorithm_name = models.CharField( 9 | max_length=50, blank=True, null=True 10 | ) 11 | start_time = models.BigIntegerField() 12 | end_time = models.BigIntegerField() 13 | result_data = JSONField(blank=True, null=True) 14 | 15 | class Meta: 16 | db_table = 'cat_result_data' 17 | -------------------------------------------------------------------------------- /nt_spark/serializers.py: -------------------------------------------------------------------------------- 1 | from rest_framework import serializers 2 | from nt_spark.models import CatResultData 3 | 4 | 5 | class CatResultDataSerializer(serializers.ModelSerializer): 6 | class Meta: 7 | model = CatResultData 8 | fields = '__all__' 9 | -------------------------------------------------------------------------------- /nt_spark/tests.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | 3 | # Create your tests here. 4 | -------------------------------------------------------------------------------- /nt_spark/urls.py: -------------------------------------------------------------------------------- 1 | from django.conf.urls import url 2 | from nt_spark.views import ( 3 | CatResultDataView 4 | ) 5 | 6 | urlpatterns = [ 7 | url(r'^cat_result$', CatResultDataView.as_view()), 8 | ] 9 | -------------------------------------------------------------------------------- /nt_spark/views.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from rest_framework.response import Response 3 | from rest_framework.views import APIView 4 | from nt_core.exceptions import RsError 5 | from nt_core.utils import get_int_or_none 6 | from nt_spark.cache import get_cache_kmeans_result 7 | 8 | 9 | class CatResultDataView(APIView): 10 | def post(self, request): 11 | req_data = request.data 12 | start_time = get_int_or_none(req_data.get('start_time')) 13 | end_time = get_int_or_none(req_data.get('end_time')) 14 | appid = get_int_or_none(req_data.get('appid')) 15 | if not all([start_time, end_time, appid]): 16 | raise RsError('缺少必要参数') 17 | 18 | algorithm_name = req_data.get('algorithm_name') 19 | if algorithm_name not in ["kmeans", "svdd", "random_forest"]: 20 | raise RsError("algorithm_name不存在") 21 | 22 | ser_data = get_cache_kmeans_result(appid, start_time, end_time) 23 | return Response(ser_data) 24 | -------------------------------------------------------------------------------- /nt_user/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/harvardfly/network_anomaly_detection/88f37dc53defb6a424f7f3124ccabc31eb9c274e/nt_user/__init__.py -------------------------------------------------------------------------------- /nt_user/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | 3 | # Register your models here. 4 | -------------------------------------------------------------------------------- /nt_user/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class NtUserConfig(AppConfig): 5 | name = 'nt_user' 6 | 7 | def ready(self): 8 | import nt_user.signals 9 | -------------------------------------------------------------------------------- /nt_user/migrations/0002_userfeedbackmessage.py: -------------------------------------------------------------------------------- 1 | # Generated by Django 2.1.2 on 2018-12-13 21:39 2 | 3 | from django.conf import settings 4 | from django.db import migrations, models 5 | import nt_core.models 6 | import uuid 7 | 8 | 9 | class Migration(migrations.Migration): 10 | 11 | dependencies = [ 12 | ('nt_user', '0001_initial'), 13 | ] 14 | 15 | operations = [ 16 | migrations.CreateModel( 17 | name='UserFeedbackMessage', 18 | fields=[ 19 | ('id', models.CharField(default=uuid.uuid4, editable=False, max_length=40, primary_key=True, serialize=False)), 20 | ('create_time', models.BigIntegerField(default=nt_core.models.get_current_time_bigint)), 21 | ('update_time', models.BigIntegerField(default=nt_core.models.get_current_time_bigint)), 22 | ('message_type', models.IntegerField(choices=[(1, '咨询'), (2, '算法反馈'), (3, '建议')], default=1, help_text='反馈类型: 1(咨询),2(算法反馈),3(建议)', verbose_name='反馈类型')), 23 | ('topic', models.CharField(default='', max_length=100, verbose_name='主题')), 24 | ('message', models.TextField(default='', help_text='反馈内容', verbose_name='反馈内容')), 25 | ('file', models.FileField(help_text='上传的文件', upload_to='message/images/', verbose_name='上传的文件')), 26 | ('user', models.ForeignKey(on_delete=True, to=settings.AUTH_USER_MODEL, verbose_name='用户')), 27 | ], 28 | options={ 29 | 'verbose_name': '用户反馈', 30 | 'verbose_name_plural': '用户反馈', 31 | }, 32 | ), 33 | ] 34 | -------------------------------------------------------------------------------- /nt_user/migrations/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/harvardfly/network_anomaly_detection/88f37dc53defb6a424f7f3124ccabc31eb9c274e/nt_user/migrations/__init__.py -------------------------------------------------------------------------------- /nt_user/signals.py: -------------------------------------------------------------------------------- 1 | from django.db.models.signals import post_save 2 | from django.dispatch import receiver 3 | from django.contrib.auth import get_user_model 4 | 5 | User = get_user_model() 6 | 7 | 8 | @receiver(post_save, sender=User) 9 | def create_user(sender, instance=None, created=False, **kwargs): 10 | if created: 11 | password = instance.password 12 | instance.set_password(password) 13 | instance.save() 14 | -------------------------------------------------------------------------------- /nt_user/tests.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | 3 | # Create your tests here. 4 | -------------------------------------------------------------------------------- /nt_user/urls.py: -------------------------------------------------------------------------------- 1 | from django.conf.urls import url 2 | from nt_user.views import ( 3 | UserViewset, FeedbackMessageViewset, ReturnUrlView 4 | ) 5 | from rest_framework.routers import DefaultRouter 6 | 7 | router = DefaultRouter() 8 | 9 | router.register( 10 | r'^users', 11 | UserViewset, 12 | base_name="users" 13 | ) 14 | 15 | # GET nt_user/users/12/ 详情 16 | 17 | router.register( 18 | r'messages', 19 | FeedbackMessageViewset, 20 | base_name="messages" 21 | ) 22 | 23 | urlpatterns = [ 24 | url(r'^index$', ReturnUrlView.as_view()) 25 | ] 26 | 27 | urlpatterns += router.urls 28 | -------------------------------------------------------------------------------- /search/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | # -*- coding:utf-8 -*- 3 | -------------------------------------------------------------------------------- /search/apps.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | # -*- coding:utf-8 -*- 3 | 4 | from django.apps import AppConfig 5 | 6 | 7 | class SearchConfig(AppConfig): 8 | name = 'search' 9 | verbose_name = '搜索' 10 | -------------------------------------------------------------------------------- /search/search_indexes.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | # -*- coding:utf-8 -*- 3 | 4 | 5 | import datetime 6 | 7 | from haystack import indexes 8 | from django.contrib.auth import get_user_model 9 | 10 | 11 | class UserIndex(indexes.SearchIndex, indexes.Indexable): 12 | """对User模型类中部分字段建立索引""" 13 | text = indexes.CharField( 14 | document=True, use_template=True, 15 | template_name='search/users_text.txt' 16 | ) # users_text.txt 保存需要建立索引的字段 17 | # python manage.py rebuild_index 建立索引 18 | 19 | def get_model(self): 20 | return get_user_model() 21 | 22 | def index_queryset(self, using=None): 23 | return self.get_model().objects.filter( 24 | date_joined__lte=datetime.datetime.now() 25 | ) 26 | -------------------------------------------------------------------------------- /social_core/__init__.py: -------------------------------------------------------------------------------- 1 | __version__ = '2.0.0' 2 | -------------------------------------------------------------------------------- /social_core/backends/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/harvardfly/network_anomaly_detection/88f37dc53defb6a424f7f3124ccabc31eb9c274e/social_core/backends/__init__.py -------------------------------------------------------------------------------- /social_core/backends/angel.py: -------------------------------------------------------------------------------- 1 | """ 2 | Angel OAuth2 backend, docs at: 3 | https://python-social-auth.readthedocs.io/en/latest/backends/angel.html 4 | """ 5 | from .oauth import BaseOAuth2 6 | 7 | 8 | class AngelOAuth2(BaseOAuth2): 9 | name = 'angel' 10 | AUTHORIZATION_URL = 'https://angel.co/api/oauth/authorize/' 11 | ACCESS_TOKEN_METHOD = 'POST' 12 | ACCESS_TOKEN_URL = 'https://angel.co/api/oauth/token/' 13 | REDIRECT_STATE = False 14 | 15 | def get_user_details(self, response): 16 | """Return user details from Angel account""" 17 | username = response['angellist_url'].split('/')[-1] 18 | email = response.get('email', '') 19 | fullname, first_name, last_name = self.get_user_names(response['name']) 20 | return {'username': username, 21 | 'fullname': fullname, 22 | 'first_name': first_name, 23 | 'last_name': last_name, 24 | 'email': email} 25 | 26 | def user_data(self, access_token, *args, **kwargs): 27 | """Loads user data from service""" 28 | return self.get_json('https://api.angel.co/1/me/', params={ 29 | 'access_token': access_token 30 | }) 31 | -------------------------------------------------------------------------------- /social_core/backends/aol.py: -------------------------------------------------------------------------------- 1 | """ 2 | AOL OpenId backend, docs at: 3 | https://python-social-auth.readthedocs.io/en/latest/backends/aol.html 4 | """ 5 | from .open_id import OpenIdAuth 6 | 7 | 8 | class AOLOpenId(OpenIdAuth): 9 | name = 'aol' 10 | URL = 'http://openid.aol.com' 11 | -------------------------------------------------------------------------------- /social_core/backends/appsfuel.py: -------------------------------------------------------------------------------- 1 | """ 2 | Appsfueld OAuth2 backend (with sandbox mode support), docs at: 3 | https://python-social-auth.readthedocs.io/en/latest/backends/appsfuel.html 4 | """ 5 | from .oauth import BaseOAuth2 6 | 7 | 8 | class AppsfuelOAuth2(BaseOAuth2): 9 | name = 'appsfuel' 10 | ID_KEY = 'user_id' 11 | AUTHORIZATION_URL = 'http://app.appsfuel.com/content/permission' 12 | ACCESS_TOKEN_URL = 'https://api.appsfuel.com/v1/live/oauth/token' 13 | ACCESS_TOKEN_METHOD = 'POST' 14 | USER_DETAILS_URL = 'https://api.appsfuel.com/v1/live/user' 15 | 16 | def get_user_details(self, response): 17 | """Return user details from Appsfuel account""" 18 | email = response.get('email', '') 19 | username = email.split('@')[0] if email else '' 20 | fullname, first_name, last_name = self.get_user_names( 21 | response.get('display_name', '') 22 | ) 23 | return { 24 | 'username': username, 25 | 'fullname': fullname, 26 | 'first_name': first_name, 27 | 'last_name': last_name, 28 | 'email': email 29 | } 30 | 31 | def user_data(self, access_token, *args, **kwargs): 32 | """Loads user data from service""" 33 | return self.get_json(self.USER_DETAILS_URL, params={ 34 | 'access_token': access_token 35 | }) 36 | 37 | 38 | class AppsfuelOAuth2Sandbox(AppsfuelOAuth2): 39 | name = 'appsfuel-sandbox' 40 | AUTHORIZATION_URL = 'https://api.appsfuel.com/v1/sandbox/choose' 41 | ACCESS_TOKEN_URL = 'https://api.appsfuel.com/v1/sandbox/oauth/token' 42 | USER_DETAILS_URL = 'https://api.appsfuel.com/v1/sandbox/user' 43 | -------------------------------------------------------------------------------- /social_core/backends/arcgis.py: -------------------------------------------------------------------------------- 1 | """ 2 | ArcGIS OAuth2 backend 3 | """ 4 | from .oauth import BaseOAuth2 5 | 6 | 7 | class ArcGISOAuth2(BaseOAuth2): 8 | name = 'arcgis' 9 | ID_KEY = 'username' 10 | AUTHORIZATION_URL = 'https://www.arcgis.com/sharing/rest/oauth2/authorize' 11 | ACCESS_TOKEN_URL = 'https://www.arcgis.com/sharing/rest/oauth2/token' 12 | ACCESS_TOKEN_METHOD = 'POST' 13 | EXTRA_DATA = [ 14 | ('expires_in', 'expires_in') 15 | ] 16 | 17 | def get_user_details(self, response): 18 | """Return user details from ArcGIS account""" 19 | return {'username': response.get('username'), 20 | 'email': response.get('email'), 21 | 'fullname': response.get('fullName'), 22 | 'first_name': response.get('firstName'), 23 | 'last_name': response.get('lastName')} 24 | 25 | def user_data(self, access_token, *args, **kwargs): 26 | """Loads user data from service""" 27 | return self.get_json( 28 | 'https://www.arcgis.com/sharing/rest/community/self', 29 | params={ 30 | 'token': access_token, 31 | 'f': 'json' 32 | } 33 | ) 34 | -------------------------------------------------------------------------------- /social_core/backends/asana.py: -------------------------------------------------------------------------------- 1 | import datetime 2 | 3 | from .oauth import BaseOAuth2 4 | 5 | 6 | class AsanaOAuth2(BaseOAuth2): 7 | name = 'asana' 8 | AUTHORIZATION_URL = 'https://app.asana.com/-/oauth_authorize' 9 | ACCESS_TOKEN_METHOD = 'POST' 10 | ACCESS_TOKEN_URL = 'https://app.asana.com/-/oauth_token' 11 | REFRESH_TOKEN_URL = 'https://app.asana.com/-/oauth_token' 12 | REDIRECT_STATE = False 13 | USER_DATA_URL = 'https://app.asana.com/api/1.0/users/me' 14 | EXTRA_DATA = [ 15 | ('expires_in', 'expires'), 16 | ('refresh_token', 'refresh_token'), 17 | ('name', 'name'), 18 | ] 19 | 20 | def get_user_details(self, response): 21 | data = response['data'] 22 | fullname, first_name, last_name = self.get_user_names(data['name']) 23 | return {'email': data['email'], 24 | 'username': data['email'], 25 | 'fullname': fullname, 26 | 'last_name': last_name, 27 | 'first_name': first_name} 28 | 29 | def user_data(self, access_token, *args, **kwargs): 30 | return self.get_json(self.USER_DATA_URL, headers={ 31 | 'Authorization': 'Bearer {}'.format(access_token) 32 | }) 33 | 34 | def extra_data(self, user, uid, response, details=None, *args, **kwargs): 35 | data = super(AsanaOAuth2, self).extra_data( 36 | user, uid, response, details 37 | ) 38 | if self.setting('ESTIMATE_EXPIRES_ON'): 39 | expires_on = datetime.datetime.utcnow() + \ 40 | datetime.timedelta(seconds=data['expires']) 41 | data['expires_on'] = expires_on.isoformat() 42 | return data 43 | -------------------------------------------------------------------------------- /social_core/backends/behance.py: -------------------------------------------------------------------------------- 1 | """ 2 | Behance OAuth2 backend, docs at: 3 | https://python-social-auth.readthedocs.io/en/latest/backends/behance.html 4 | """ 5 | from .oauth import BaseOAuth2 6 | 7 | 8 | class BehanceOAuth2(BaseOAuth2): 9 | """Behance OAuth authentication backend""" 10 | name = 'behance' 11 | AUTHORIZATION_URL = 'https://www.behance.net/v2/oauth/authenticate' 12 | ACCESS_TOKEN_URL = 'https://www.behance.net/v2/oauth/token' 13 | ACCESS_TOKEN_METHOD = 'POST' 14 | SCOPE_SEPARATOR = '|' 15 | EXTRA_DATA = [('username', 'username')] 16 | REDIRECT_STATE = False 17 | 18 | def get_user_id(self, details, response): 19 | return response['user']['id'] 20 | 21 | def get_user_details(self, response): 22 | """Return user details from Behance account""" 23 | user = response['user'] 24 | fullname, first_name, last_name = self.get_user_names( 25 | user['display_name'], user['first_name'], user['last_name'] 26 | ) 27 | return {'username': user['username'], 28 | 'fullname': fullname, 29 | 'first_name': first_name, 30 | 'last_name': last_name, 31 | 'email': ''} 32 | 33 | def extra_data(self, user, uid, response, details=None, *args, **kwargs): 34 | # Pull up the embedded user attributes so they can be found as extra 35 | # data. See the example token response for possible attributes: 36 | # http://www.behance.net/dev/authentication#step-by-step 37 | data = response.copy() 38 | data.update(response['user']) 39 | return super(BehanceOAuth2, self).extra_data(user, uid, data, details, 40 | *args, **kwargs) 41 | -------------------------------------------------------------------------------- /social_core/backends/belgiumeid.py: -------------------------------------------------------------------------------- 1 | """ 2 | Belgium EID OpenId backend, docs at: 3 | https://python-social-auth.readthedocs.io/en/latest/backends/belgium_eid.html 4 | """ 5 | from .open_id import OpenIdAuth 6 | 7 | 8 | class BelgiumEIDOpenId(OpenIdAuth): 9 | """Belgium e-ID OpenID authentication backend""" 10 | name = 'belgiumeid' 11 | URL = 'https://www.e-contract.be/eid-idp/endpoints/openid/auth' 12 | -------------------------------------------------------------------------------- /social_core/backends/changetip.py: -------------------------------------------------------------------------------- 1 | from .oauth import BaseOAuth2 2 | 3 | 4 | class ChangeTipOAuth2(BaseOAuth2): 5 | """ChangeTip OAuth authentication backend 6 | https://www.changetip.com/api 7 | """ 8 | name = 'changetip' 9 | AUTHORIZATION_URL = 'https://www.changetip.com/o/authorize/' 10 | ACCESS_TOKEN_URL = 'https://www.changetip.com/o/token/' 11 | ACCESS_TOKEN_METHOD = 'POST' 12 | SCOPE_SEPARATOR = ' ' 13 | 14 | def get_user_details(self, response): 15 | """Return user details from ChangeTip account""" 16 | return { 17 | 'username': response['username'], 18 | 'email': response.get('email', ''), 19 | 'first_name': '', 20 | 'last_name': '', 21 | } 22 | 23 | def user_data(self, access_token, *args, **kwargs): 24 | """Loads user data from service""" 25 | return self.get_json('https://api.changetip.com/v2/me/', params={ 26 | 'access_token': access_token 27 | }) 28 | -------------------------------------------------------------------------------- /social_core/backends/classlink.py: -------------------------------------------------------------------------------- 1 | from .oauth import BaseOAuth2 2 | 3 | 4 | class ClasslinkOAuth(BaseOAuth2): 5 | """ 6 | Classlink OAuth authentication backend. 7 | 8 | Docs: https://developer.classlink.com/docs/oauth2-workflow 9 | """ 10 | name = 'classlink' 11 | AUTHORIZATION_URL = 'https://launchpad.classlink.com/oauth2/v2/auth' 12 | ACCESS_TOKEN_URL = 'https://launchpad.classlink.com/oauth2/v2/token' 13 | ACCESS_TOKEN_METHOD = 'POST' 14 | DEFAULT_SCOPE = ['profile'] 15 | REDIRECT_STATE = False 16 | SCOPE_SEPARATOR = ' ' 17 | 18 | def get_user_id(self, details, response): 19 | """Return user unique id provided by service""" 20 | return response['UserId'] 21 | 22 | def get_user_details(self, response): 23 | """Return user details from Classlink account""" 24 | fullname, first_name, last_name = self.get_user_names( 25 | first_name=response.get('FirstName'), 26 | last_name=response.get('LastName') 27 | ) 28 | 29 | return { 30 | 'username': response.get('Email') or response.get('LoginId'), 31 | 'email': response.get('Email'), 32 | 'fullname': fullname, 33 | 'first_name': first_name, 34 | 'last_name': last_name, 35 | } 36 | 37 | def user_data(self, token, *args, **kwargs): 38 | """Loads user data from service""" 39 | url = 'https://nodeapi.classlink.com/v2/my/info' 40 | auth_header = {"Authorization": "Bearer %s" % token} 41 | try: 42 | return self.get_json(url, headers=auth_header) 43 | except ValueError: 44 | return None 45 | -------------------------------------------------------------------------------- /social_core/backends/coding.py: -------------------------------------------------------------------------------- 1 | """ 2 | Coding OAuth2 backend, docs at: 3 | """ 4 | from six.moves.urllib.parse import urljoin 5 | 6 | from .oauth import BaseOAuth2 7 | 8 | 9 | class CodingOAuth2(BaseOAuth2): 10 | """Coding OAuth authentication backend""" 11 | 12 | name = 'coding' 13 | API_URL = 'https://coding.net/api/' 14 | AUTHORIZATION_URL = 'https://coding.net/oauth_authorize.html' 15 | ACCESS_TOKEN_URL = 'https://coding.net/api/oauth/access_token' 16 | ACCESS_TOKEN_METHOD = 'POST' 17 | SCOPE_SEPARATOR = ',' 18 | DEFAULT_SCOPE = ['user'] 19 | REDIRECT_STATE = False 20 | 21 | def api_url(self): 22 | return self.API_URL 23 | 24 | def get_user_details(self, response): 25 | """Return user details from Github account""" 26 | fullname, first_name, last_name = self.get_user_names( 27 | response.get('name') 28 | ) 29 | return {'username': response.get('name'), 30 | 'email': response.get('email') or '', 31 | 'fullname': fullname, 32 | 'first_name': first_name, 33 | 'last_name': last_name} 34 | 35 | def user_data(self, access_token, *args, **kwargs): 36 | """Loads user data from service""" 37 | data = self._user_data(access_token) 38 | if data.get('code') != 0: 39 | # 获取失败 40 | pass 41 | return data.get('data') 42 | 43 | def _user_data(self, access_token, path=None): 44 | url = urljoin( 45 | self.api_url(), 46 | 'account/current_user{0}'.format(path or '') 47 | ) 48 | return self.get_json(url, params={'access_token': access_token}) 49 | -------------------------------------------------------------------------------- /social_core/backends/coinbase.py: -------------------------------------------------------------------------------- 1 | """ 2 | Coinbase OAuth2 backend, docs at: 3 | https://python-social-auth.readthedocs.io/en/latest/backends/coinbase.html 4 | """ 5 | from .oauth import BaseOAuth2 6 | 7 | 8 | class CoinbaseOAuth2(BaseOAuth2): 9 | name = 'coinbase' 10 | SCOPE_SEPARATOR = '+' 11 | DEFAULT_SCOPE = ['user', 'balance'] 12 | AUTHORIZATION_URL = 'https://www.coinbase.com/oauth/authorize' 13 | ACCESS_TOKEN_URL = 'https://api.coinbase.com/oauth/token' 14 | REVOKE_TOKEN_URL = 'https://api.coinbase.com/oauth/revoke' 15 | ACCESS_TOKEN_METHOD = 'POST' 16 | REDIRECT_STATE = False 17 | 18 | def get_user_id(self, details, response): 19 | return response['data']['id'] 20 | 21 | def get_user_details(self, response): 22 | """Return user details from Coinbase account""" 23 | user_data = response['data'] 24 | email = user_data.get('email', '') 25 | name = user_data['name'] 26 | username = user_data.get('username') 27 | fullname, first_name, last_name = self.get_user_names(name) 28 | return {'username': username, 29 | 'fullname': fullname, 30 | 'first_name': first_name, 31 | 'last_name': last_name, 32 | 'email': email} 33 | 34 | def user_data(self, access_token, *args, **kwargs): 35 | """Loads user data from service""" 36 | return self.get_json('https://api.coinbase.com/v2/user', 37 | headers={'Authorization': 'Bearer ' + access_token}) 38 | -------------------------------------------------------------------------------- /social_core/backends/coursera.py: -------------------------------------------------------------------------------- 1 | """ 2 | Coursera OAuth2 backend, docs at: 3 | https://tech.coursera.org/app-platform/oauth2/ 4 | """ 5 | from .oauth import BaseOAuth2 6 | 7 | 8 | class CourseraOAuth2(BaseOAuth2): 9 | """Coursera OAuth2 authentication backend""" 10 | name = 'coursera' 11 | ID_KEY = 'username' 12 | AUTHORIZATION_URL = 'https://accounts.coursera.org/oauth2/v1/auth' 13 | ACCESS_TOKEN_URL = 'https://accounts.coursera.org/oauth2/v1/token' 14 | ACCESS_TOKEN_METHOD = 'POST' 15 | REDIRECT_STATE = False 16 | SCOPE_SEPARATOR = ',' 17 | DEFAULT_SCOPE = ['view_profile'] 18 | 19 | def _get_username_from_response(self, response): 20 | elements = response.get('elements', []) 21 | for element in elements: 22 | if 'id' in element: 23 | return element.get('id') 24 | 25 | return None 26 | 27 | def get_user_details(self, response): 28 | """Return user details from Coursera account""" 29 | return {'username': self._get_username_from_response(response)} 30 | 31 | def get_user_id(self, details, response): 32 | """Return a username prepared in get_user_details as uid""" 33 | return details.get(self.ID_KEY) 34 | 35 | def user_data(self, access_token, *args, **kwargs): 36 | """Load user data from the service""" 37 | return self.get_json( 38 | 'https://api.coursera.org/api/externalBasicProfiles.v1?q=me', 39 | headers=self.get_auth_header(access_token) 40 | ) 41 | 42 | def get_auth_header(self, access_token): 43 | return {'Authorization': 'Bearer {0}'.format(access_token)} 44 | -------------------------------------------------------------------------------- /social_core/backends/dailymotion.py: -------------------------------------------------------------------------------- 1 | """ 2 | DailyMotion OAuth2 backend, docs at: 3 | https://python-social-auth.readthedocs.io/en/latest/backends/dailymotion.html 4 | """ 5 | from .oauth import BaseOAuth2 6 | 7 | 8 | class DailymotionOAuth2(BaseOAuth2): 9 | """Dailymotion OAuth authentication backend""" 10 | name = 'dailymotion' 11 | EXTRA_DATA = [('id', 'id')] 12 | ID_KEY = 'username' 13 | AUTHORIZATION_URL = 'https://api.dailymotion.com/oauth/authorize' 14 | REQUEST_TOKEN_URL = 'https://api.dailymotion.com/oauth/token' 15 | ACCESS_TOKEN_URL = 'https://api.dailymotion.com/oauth/token' 16 | ACCESS_TOKEN_METHOD = 'POST' 17 | 18 | def get_user_details(self, response): 19 | return {'username': response.get('screenname')} 20 | 21 | def user_data(self, access_token, *args, **kwargs): 22 | """Return user data provided""" 23 | return self.get_json('https://api.dailymotion.com/auth/', 24 | params={'access_token': access_token}) 25 | -------------------------------------------------------------------------------- /social_core/backends/digitalocean.py: -------------------------------------------------------------------------------- 1 | from .oauth import BaseOAuth2 2 | 3 | 4 | class DigitalOceanOAuth(BaseOAuth2): 5 | """ 6 | DigitalOcean OAuth authentication backend. 7 | 8 | Docs: https://developers.digitalocean.com/documentation/oauth/ 9 | """ 10 | name = 'digitalocean' 11 | AUTHORIZATION_URL = 'https://cloud.digitalocean.com/v1/oauth/authorize' 12 | ACCESS_TOKEN_URL = 'https://cloud.digitalocean.com/v1/oauth/token' 13 | ACCESS_TOKEN_METHOD = 'POST' 14 | SCOPE_SEPARATOR = ' ' 15 | EXTRA_DATA = [ 16 | ('expires_in', 'expires_in') 17 | ] 18 | 19 | def get_user_id(self, details, response): 20 | """Return user unique id provided by service""" 21 | return response['account'].get('uuid') 22 | 23 | def get_user_details(self, response): 24 | """Return user details from DigitalOcean account""" 25 | fullname, first_name, last_name = self.get_user_names( 26 | response.get('name') or '') 27 | 28 | return {'username': response['account'].get('email'), 29 | 'email': response['account'].get('email'), 30 | 'fullname': fullname, 31 | 'first_name': first_name, 32 | 'last_name': last_name} 33 | 34 | def user_data(self, token, *args, **kwargs): 35 | """Loads user data from service""" 36 | url = 'https://api.digitalocean.com/v2/account' 37 | auth_header = {"Authorization": "Bearer %s" % token} 38 | try: 39 | return self.get_json(url, headers=auth_header) 40 | except ValueError: 41 | return None 42 | -------------------------------------------------------------------------------- /social_core/backends/discord.py: -------------------------------------------------------------------------------- 1 | """ 2 | Discord Auth OAuth2 backend, docs at: 3 | https://discordapp.com/developers/docs/topics/oauth2 4 | """ 5 | from .oauth import BaseOAuth2 6 | 7 | 8 | class DiscordOAuth2(BaseOAuth2): 9 | name = 'discord' 10 | AUTHORIZATION_URL = 'https://discordapp.com/api/oauth2/authorize' 11 | ACCESS_TOKEN_URL = 'https://discordapp.com/api/oauth2/token' 12 | ACCESS_TOKEN_METHOD = 'POST' 13 | REVOKE_TOKEN_URL = 'https://discordapp.com/api/oauth2/token/revoke' 14 | REVOKE_TOKEN_METHOD = 'GET' 15 | DEFAULT_SCOPE = ['identify'] 16 | SCOPE_SEPARATOR = '+' 17 | REDIRECT_STATE = False 18 | EXTRA_DATA = [ 19 | ('expires_in', 'expires'), 20 | ('refresh_token', 'refresh_token') 21 | ] 22 | 23 | def get_user_details(self, response): 24 | return {'username': response.get('username'), 25 | 'email': response.get('email') or ''} 26 | 27 | def user_data(self, access_token, *args, **kwargs): 28 | url = 'https://discordapp.com/api/users/@me' 29 | auth_header = {"Authorization": "Bearer %s" % access_token} 30 | return self.get_json(url, headers=auth_header) 31 | -------------------------------------------------------------------------------- /social_core/backends/drip.py: -------------------------------------------------------------------------------- 1 | """ 2 | Drip OAuth2 backend, docs at: 3 | https://python-social-auth.readthedocs.io/en/latest/backends/drip.html 4 | """ 5 | from .oauth import BaseOAuth2 6 | 7 | 8 | class DripOAuth(BaseOAuth2): 9 | name = 'drip' 10 | AUTHORIZATION_URL = 'https://www.getdrip.com/oauth/authorize' 11 | ACCESS_TOKEN_URL = 'https://www.getdrip.com/oauth/token' 12 | ACCESS_TOKEN_METHOD = 'POST' 13 | 14 | def get_user_id(self, details, response): 15 | return details['email'] 16 | 17 | def get_user_details(self, response): 18 | return {'email': response['users'][0]['email'], 19 | 'fullname': response['users'][0]['name'], 20 | 'username': response['users'][0]['email']} 21 | 22 | def user_data(self, access_token, *args, **kwargs): 23 | return self.get_json('https://api.getdrip.com/v2/user', headers={ 24 | 'Authorization': 'Bearer %s' % access_token 25 | }) 26 | -------------------------------------------------------------------------------- /social_core/backends/echosign.py: -------------------------------------------------------------------------------- 1 | from .oauth import BaseOAuth2 2 | 3 | 4 | class EchosignOAuth2(BaseOAuth2): 5 | name = 'echosign' 6 | REDIRECT_STATE = False 7 | ACCESS_TOKEN_METHOD = 'POST' 8 | REFRESH_TOKEN_METHOD = 'POST' 9 | REVOKE_TOKEN_METHOD = 'POST' 10 | AUTHORIZATION_URL = 'https://secure.echosign.com/public/oauth' 11 | ACCESS_TOKEN_URL = 'https://secure.echosign.com/oauth/token' 12 | REFRESH_TOKEN_URL = 'https://secure.echosign.com/oauth/refresh' 13 | REVOKE_TOKEN_URL = 'https://secure.echosign.com/oauth/revoke' 14 | 15 | def get_user_details(self, response): 16 | return response 17 | 18 | def get_user_id(self, details, response): 19 | return details['userInfoList'][0]['userId'] 20 | 21 | def user_data(self, access_token, *args, **kwargs): 22 | return self.get_json( 23 | 'https://api.echosign.com/api/rest/v3/users', 24 | headers={'Access-Token': access_token}) 25 | -------------------------------------------------------------------------------- /social_core/backends/edmodo.py: -------------------------------------------------------------------------------- 1 | """ 2 | Edmodo OAuth2 Sign-in backend, docs at: 3 | https://python-social-auth.readthedocs.io/en/latest/backends/edmodo.html 4 | """ 5 | from .oauth import BaseOAuth2 6 | 7 | 8 | class EdmodoOAuth2(BaseOAuth2): 9 | """Edmodo OAuth2""" 10 | name = 'edmodo' 11 | AUTHORIZATION_URL = 'https://api.edmodo.com/oauth/authorize' 12 | ACCESS_TOKEN_URL = 'https://api.edmodo.com/oauth/token' 13 | ACCESS_TOKEN_METHOD = 'POST' 14 | 15 | def get_user_details(self, response): 16 | """Return user details from Edmodo account""" 17 | fullname, first_name, last_name = self.get_user_names( 18 | first_name=response.get('first_name'), 19 | last_name=response.get('last_name') 20 | ) 21 | return { 22 | 'username': response.get('username'), 23 | 'email': response.get('email'), 24 | 'fullname': fullname, 25 | 'first_name': first_name, 26 | 'last_name': last_name 27 | } 28 | 29 | def user_data(self, access_token, *args, **kwargs): 30 | """Loads user data from Edmodo""" 31 | return self.get_json( 32 | 'https://api.edmodo.com/users/me', 33 | params={'access_token': access_token} 34 | ) 35 | -------------------------------------------------------------------------------- /social_core/backends/elixir.py: -------------------------------------------------------------------------------- 1 | """ 2 | Backend for OpenID Connect ELIXIR AAI 3 | https://www.elixir-europe.org/services/compute/aai 4 | """ 5 | 6 | from social_core.backends.open_id_connect import OpenIdConnectAuth 7 | 8 | 9 | class ElixirOpenIdConnect(OpenIdConnectAuth): 10 | name = 'elixir' 11 | OIDC_ENDPOINT = 'https://login.elixir-czech.org/oidc' 12 | EXTRA_DATA = [ 13 | ('expires_in', 'expires_in', True), 14 | ('refresh_token', 'refresh_token', True), 15 | ('id_token', 'id_token', True), 16 | ('other_tokens', 'other_tokens', True), 17 | ] 18 | 19 | def get_user_details(self, response): 20 | username_key = self.setting('USERNAME_KEY', default=self.USERNAME_KEY) 21 | name = response.get('name') or '' 22 | fullname, first_name, last_name = self.get_user_names(name) 23 | return {'username': response.get(username_key), 24 | 'email': response.get('email'), 25 | 'fullname': fullname, 26 | 'first_name': first_name, 27 | 'last_name': last_name} 28 | -------------------------------------------------------------------------------- /social_core/backends/email.py: -------------------------------------------------------------------------------- 1 | """ 2 | Legacy Email backend, docs at: 3 | https://python-social-auth.readthedocs.io/en/latest/backends/email.html 4 | """ 5 | from .legacy import LegacyAuth 6 | 7 | 8 | class EmailAuth(LegacyAuth): 9 | name = 'email' 10 | ID_KEY = 'email' 11 | REQUIRES_EMAIL_VALIDATION = True 12 | EXTRA_DATA = ['email'] 13 | -------------------------------------------------------------------------------- /social_core/backends/eventbrite.py: -------------------------------------------------------------------------------- 1 | from .oauth import BaseOAuth2 2 | 3 | 4 | class EventbriteOAuth2(BaseOAuth2): 5 | """Eventbrite OAuth2 authentication backend""" 6 | name = 'eventbrite' 7 | AUTHORIZATION_URL = 'https://www.eventbrite.com/oauth/authorize' 8 | ACCESS_TOKEN_URL = 'https://www.eventbrite.com/oauth/token' 9 | METADATA_URL = 'https://www.eventbriteapi.com/v3/users/me' 10 | ACCESS_TOKEN_METHOD = 'POST' 11 | STATE_PARAMETER = False 12 | REDIRECT_STATE = False 13 | 14 | def get_user_details(self, response): 15 | """Return user details from an Eventbrite metadata response""" 16 | email = next(iter(filter(lambda x: x['primary'], response['emails'])))['email'] 17 | 18 | return { 19 | 'username': email, 20 | 'email': email, 21 | 'first_name': response['first_name'], 22 | 'last_name': response['last_name'] 23 | } 24 | 25 | def user_data(self, access_token, *args, **kwargs): 26 | """Loads user data and datacenter information from service""" 27 | return self.get_json(self.METADATA_URL, headers={ 28 | 'Authorization': 'Bearer ' + access_token 29 | }) 30 | -------------------------------------------------------------------------------- /social_core/backends/eveonline.py: -------------------------------------------------------------------------------- 1 | """ 2 | EVE Online Single Sign-On (SSO) OAuth2 backend 3 | Documentation at https://eveonline-third-party-documentation.readthedocs.io/en/latest/sso/index.html 4 | """ 5 | from .oauth import BaseOAuth2 6 | 7 | 8 | class EVEOnlineOAuth2(BaseOAuth2): 9 | """EVE Online OAuth authentication backend""" 10 | name = 'eveonline' 11 | BASE_URL = 'https://login.eveonline.com/oauth' 12 | AUTHORIZATION_URL = BASE_URL + '/authorize' 13 | ACCESS_TOKEN_URL = BASE_URL + '/token' 14 | ID_KEY = 'CharacterID' 15 | ACCESS_TOKEN_METHOD = 'POST' 16 | EXTRA_DATA = [ 17 | ('CharacterID', 'id'), 18 | ('expires_in', 'expires'), 19 | ('CharacterOwnerHash', 'owner_hash', True), 20 | ('refresh_token', 'refresh_token', True), 21 | ] 22 | 23 | def get_user_details(self, response): 24 | """Return user details from EVE Online account""" 25 | user_data = self.user_data(response['access_token']) 26 | fullname, first_name, last_name = self.get_user_names( 27 | user_data['CharacterName'] 28 | ) 29 | return { 30 | 'email': '', 31 | 'username': fullname, 32 | 'fullname': fullname, 33 | 'first_name': first_name, 34 | 'last_name': last_name 35 | } 36 | 37 | def user_data(self, access_token, *args, **kwargs): 38 | """Get Character data from EVE server""" 39 | return self.get_json( 40 | 'https://login.eveonline.com/oauth/verify', 41 | headers={'Authorization': 'Bearer {0}'.format(access_token)} 42 | ) 43 | -------------------------------------------------------------------------------- /social_core/backends/fedora.py: -------------------------------------------------------------------------------- 1 | """ 2 | Fedora OpenId backend, docs at: 3 | https://python-social-auth.readthedocs.io/en/latest/backends/fedora.html 4 | """ 5 | from .open_id import OpenIdAuth 6 | 7 | 8 | class FedoraOpenId(OpenIdAuth): 9 | name = 'fedora' 10 | URL = 'https://id.fedoraproject.org' 11 | USERNAME_KEY = 'nickname' 12 | -------------------------------------------------------------------------------- /social_core/backends/five_hundred_px.py: -------------------------------------------------------------------------------- 1 | """ 2 | 500px OAuth1 backend, docs at: 3 | https://python-social-auth.readthedocs.io/en/latest/backends/five_hundred_px.html 4 | """ 5 | from .oauth import BaseOAuth1 6 | 7 | 8 | class FiveHundredPxOAuth(BaseOAuth1): 9 | """500px OAuth authentication backend""" 10 | name = '500px' 11 | AUTHORIZATION_URL = 'https://api.500px.com/v1/oauth/authorize' 12 | REQUEST_TOKEN_URL = 'https://api.500px.com/v1/oauth/request_token' 13 | ACCESS_TOKEN_URL = 'https://api.500px.com/v1/oauth/access_token' 14 | 15 | def get_user_details(self, user): 16 | """Return user details from 500px account""" 17 | fullname, first_name, last_name = self.get_user_names( 18 | user.get('fullname') 19 | ) 20 | return { 21 | 'username': user.get('username') or user.get('id'), 22 | 'email': user.get('email'), 23 | 'fullname': fullname, 24 | 'first_name': first_name, 25 | 'last_name': last_name 26 | } 27 | 28 | def user_data(self, access_token, *args, **kwargs): 29 | """Return user data provided""" 30 | response = self.get_json( 31 | 'https://api.500px.com/v1/users', 32 | auth=self.oauth_auth(access_token) 33 | ) 34 | return response.get('user') 35 | -------------------------------------------------------------------------------- /social_core/backends/flat.py: -------------------------------------------------------------------------------- 1 | """ 2 | Flat OAuth2 backend, docs at: 3 | https://python-social-auth.readthedocs.io/en/latest/backends/flat.html 4 | """ 5 | from .oauth import BaseOAuth2 6 | 7 | 8 | class FlatOAuth2(BaseOAuth2): 9 | """Flat OAuth2""" 10 | name = 'flat' 11 | DEFAULT_SCOPE = ['account.public_profile'] 12 | AUTHORIZATION_URL = 'https://flat.io/auth/oauth' 13 | ACCESS_TOKEN_URL = 'https://api.flat.io/oauth/access_token' 14 | ACCESS_TOKEN_METHOD = 'POST' 15 | 16 | def get_user_id(self, details, response): 17 | return response.get('id') 18 | 19 | def get_user_details(self, response): 20 | """Return user details from Flat account""" 21 | return { 22 | 'email': response.get('email'), 23 | 'username': response.get('username'), 24 | 'fullname': response.get('printableName') 25 | } 26 | 27 | def user_data(self, access_token, *args, **kwargs): 28 | """Loads user data from service""" 29 | return self.get_json('https://api.flat.io/v2/me', headers={ 30 | 'Authorization': 'Bearer ' + access_token 31 | }) 32 | -------------------------------------------------------------------------------- /social_core/backends/flickr.py: -------------------------------------------------------------------------------- 1 | """ 2 | Flickr OAuth1 backend, docs at: 3 | https://python-social-auth.readthedocs.io/en/latest/backends/flickr.html 4 | """ 5 | from .oauth import BaseOAuth1 6 | 7 | 8 | class FlickrOAuth(BaseOAuth1): 9 | """Flickr OAuth authentication backend""" 10 | name = 'flickr' 11 | AUTHORIZATION_URL = 'https://www.flickr.com/services/oauth/authorize' 12 | REQUEST_TOKEN_URL = 'https://www.flickr.com/services/oauth/request_token' 13 | ACCESS_TOKEN_URL = 'https://www.flickr.com/services/oauth/access_token' 14 | EXTRA_DATA = [ 15 | ('id', 'id'), 16 | ('username', 'username'), 17 | ('expires', 'expires') 18 | ] 19 | 20 | def get_user_details(self, response): 21 | """Return user details from Flickr account""" 22 | fullname, first_name, last_name = self.get_user_names( 23 | response.get('fullname') 24 | ) 25 | return {'username': response.get('username') or response.get('id'), 26 | 'email': '', 27 | 'fullname': fullname, 28 | 'first_name': first_name, 29 | 'last_name': last_name} 30 | 31 | def user_data(self, access_token, *args, **kwargs): 32 | """Loads user data from service""" 33 | return { 34 | 'id': access_token['user_nsid'], 35 | 'username': access_token['username'], 36 | 'fullname': access_token.get('fullname', ''), 37 | } 38 | 39 | def auth_extra_arguments(self): 40 | params = super(FlickrOAuth, self).auth_extra_arguments() or {} 41 | if 'perms' not in params: 42 | params['perms'] = 'read' 43 | return params 44 | -------------------------------------------------------------------------------- /social_core/backends/foursquare.py: -------------------------------------------------------------------------------- 1 | """ 2 | Foursquare OAuth2 backend, docs at: 3 | https://python-social-auth.readthedocs.io/en/latest/backends/foursquare.html 4 | """ 5 | from .oauth import BaseOAuth2 6 | 7 | 8 | class FoursquareOAuth2(BaseOAuth2): 9 | name = 'foursquare' 10 | AUTHORIZATION_URL = 'https://foursquare.com/oauth2/authenticate' 11 | ACCESS_TOKEN_URL = 'https://foursquare.com/oauth2/access_token' 12 | ACCESS_TOKEN_METHOD = 'POST' 13 | API_VERSION = '20140128' 14 | 15 | def get_user_id(self, details, response): 16 | return response['response']['user']['id'] 17 | 18 | def get_user_details(self, response): 19 | """Return user details from Foursquare account""" 20 | info = response['response']['user'] 21 | email = info['contact']['email'] 22 | fullname, first_name, last_name = self.get_user_names( 23 | first_name=info.get('firstName', ''), 24 | last_name=info.get('lastName', '') 25 | ) 26 | return {'username': first_name + ' ' + last_name, 27 | 'fullname': fullname, 28 | 'first_name': first_name, 29 | 'last_name': last_name, 30 | 'email': email} 31 | 32 | def user_data(self, access_token, *args, **kwargs): 33 | """Loads user data from service""" 34 | return self.get_json('https://api.foursquare.com/v2/users/self', 35 | params={'oauth_token': access_token, 36 | 'v': self.API_VERSION}) 37 | -------------------------------------------------------------------------------- /social_core/backends/gae.py: -------------------------------------------------------------------------------- 1 | """ 2 | Google App Engine support using User API 3 | """ 4 | from __future__ import absolute_import 5 | 6 | from google.appengine.api import users 7 | 8 | from .base import BaseAuth 9 | from ..exceptions import AuthException 10 | 11 | 12 | class GoogleAppEngineAuth(BaseAuth): 13 | """GoogleAppengine authentication backend""" 14 | name = 'google-appengine' 15 | 16 | def get_user_id(self, details, response): 17 | """Return current user id.""" 18 | user = users.get_current_user() 19 | if user: 20 | return user.user_id() 21 | 22 | def get_user_details(self, response): 23 | """Return user basic information (id and email only).""" 24 | user = users.get_current_user() 25 | return {'username': user.user_id(), 26 | 'email': user.email(), 27 | 'fullname': '', 28 | 'first_name': '', 29 | 'last_name': ''} 30 | 31 | def auth_url(self): 32 | """Build and return complete URL.""" 33 | return users.create_login_url(self.redirect_uri) 34 | 35 | def auth_complete(self, *args, **kwargs): 36 | """Completes login process, must return user instance.""" 37 | if not users.get_current_user(): 38 | raise AuthException('Authentication error') 39 | kwargs.update({'response': '', 'backend': self}) 40 | return self.strategy.authenticate(*args, **kwargs) 41 | -------------------------------------------------------------------------------- /social_core/backends/github_enterprise.py: -------------------------------------------------------------------------------- 1 | """ 2 | Github Enterprise OAuth2 backend, docs at: 3 | https://python-social-auth.readthedocs.io/en/latest/backends/github_enterprise.html 4 | """ 5 | from six.moves.urllib.parse import urljoin 6 | 7 | from ..utils import append_slash 8 | from .github import GithubOAuth2, GithubOrganizationOAuth2, \ 9 | GithubTeamOAuth2 10 | 11 | 12 | class GithubEnterpriseMixin(object): 13 | def api_url(self): 14 | return append_slash(self.setting('API_URL')) 15 | 16 | def authorization_url(self): 17 | return self._url('login/oauth/authorize') 18 | 19 | def access_token_url(self): 20 | return self._url('login/oauth/access_token') 21 | 22 | def _url(self, path): 23 | return urljoin(append_slash(self.setting('URL')), path) 24 | 25 | 26 | class GithubEnterpriseOAuth2(GithubEnterpriseMixin, GithubOAuth2): 27 | """Github Enterprise OAuth authentication backend""" 28 | name = 'github-enterprise' 29 | 30 | 31 | class GithubEnterpriseOrganizationOAuth2(GithubEnterpriseMixin, 32 | GithubOrganizationOAuth2): 33 | """Github Enterprise OAuth2 authentication backend for 34 | organizations""" 35 | name = 'github-enterprise-org' 36 | DEFAULT_SCOPE = ['read:org'] 37 | 38 | 39 | class GithubEnterpriseTeamOAuth2(GithubEnterpriseMixin, GithubTeamOAuth2): 40 | """Github Enterprise OAuth2 authentication backend for teams""" 41 | name = 'github-enterprise-team' 42 | DEFAULT_SCOPE = ['read:org'] 43 | -------------------------------------------------------------------------------- /social_core/backends/globus.py: -------------------------------------------------------------------------------- 1 | """ 2 | Globus Auth OpenID Connect backend, docs at: 3 | https://docs.globus.org/api/auth 4 | http://globus-integration-examples.readthedocs.io 5 | """ 6 | 7 | from social_core.backends.open_id_connect import OpenIdConnectAuth 8 | 9 | 10 | class GlobusOpenIdConnect(OpenIdConnectAuth): 11 | name = 'globus' 12 | OIDC_ENDPOINT = 'https://auth.globus.org' 13 | EXTRA_DATA = [ 14 | ('expires_in', 'expires_in', True), 15 | ('refresh_token', 'refresh_token', True), 16 | ('id_token', 'id_token', True), 17 | ('other_tokens', 'other_tokens', True), 18 | ] 19 | 20 | def get_user_details(self, response): 21 | username_key = self.setting('USERNAME_KEY', default=self.USERNAME_KEY) 22 | name = response.get('name') or '' 23 | fullname, first_name, last_name = self.get_user_names(name) 24 | return {'username': response.get(username_key), 25 | 'email': response.get('email'), 26 | 'fullname': fullname, 27 | 'first_name': first_name, 28 | 'last_name': last_name} 29 | -------------------------------------------------------------------------------- /social_core/backends/goclio.py: -------------------------------------------------------------------------------- 1 | from .oauth import BaseOAuth2 2 | 3 | 4 | class GoClioOAuth2(BaseOAuth2): 5 | name = 'goclio' 6 | AUTHORIZATION_URL = 'https://app.goclio.com/oauth/authorize/' 7 | ACCESS_TOKEN_METHOD = 'POST' 8 | ACCESS_TOKEN_URL = 'https://app.goclio.com/oauth/token/' 9 | REDIRECT_STATE = False 10 | STATE_PARAMETER = False 11 | 12 | def get_user_details(self, response): 13 | """Return user details from GoClio account""" 14 | user = response.get('user', {}) 15 | username = user.get('id', None) 16 | email = user.get('email', None) 17 | first_name, last_name = (user.get('first_name', None), 18 | user.get('last_name', None)) 19 | fullname = '%s %s' % (first_name, last_name) 20 | 21 | return {'username': username, 22 | 'fullname': fullname, 23 | 'first_name': first_name, 24 | 'last_name': last_name, 25 | 'email': email} 26 | 27 | def user_data(self, access_token, *args, **kwargs): 28 | """Loads user data from service""" 29 | return self.get_json( 30 | 'https://app.goclio.com/api/v2/users/who_am_i', 31 | params={'access_token': access_token} 32 | ) 33 | 34 | def get_user_id(self, details, response): 35 | return response.get('user', {}).get('id') 36 | -------------------------------------------------------------------------------- /social_core/backends/goclioeu.py: -------------------------------------------------------------------------------- 1 | from .goclio import GoClioOAuth2 2 | 3 | 4 | class GoClioEuOAuth2(GoClioOAuth2): 5 | name = 'goclioeu' 6 | AUTHORIZATION_URL = 'https://app.goclio.eu/oauth/authorize/' 7 | ACCESS_TOKEN_URL = 'https://app.goclio.eu/oauth/token/' 8 | 9 | def user_data(self, access_token, *args, **kwargs): 10 | """Loads user data from service""" 11 | return self.get_json( 12 | 'https://app.goclio.eu/api/v2/users/who_am_i', 13 | params={'access_token': access_token} 14 | ) 15 | -------------------------------------------------------------------------------- /social_core/backends/google_openidconnect.py: -------------------------------------------------------------------------------- 1 | """ 2 | Google OpenIdConnect: 3 | https://python-social-auth.readthedocs.io/en/latest/backends/google.html 4 | """ 5 | from .open_id_connect import OpenIdConnectAuth 6 | from .google import GoogleOAuth2 7 | 8 | 9 | class GoogleOpenIdConnect(GoogleOAuth2, OpenIdConnectAuth): 10 | name = 'google-openidconnect' 11 | OIDC_ENDPOINT = 'https://accounts.google.com' 12 | # differs from value in discovery document 13 | # http://openid.net/specs/openid-connect-core-1_0.html#rfc.section.15.6.2 14 | ID_TOKEN_ISSUER = 'accounts.google.com' 15 | 16 | def user_data(self, access_token, *args, **kwargs): 17 | """Return user data from Google API""" 18 | return self.get_json( 19 | 'https://www.googleapis.com/plus/v1/people/me/openIdConnect', 20 | params={'access_token': access_token, 'alt': 'json'} 21 | ) 22 | -------------------------------------------------------------------------------- /social_core/backends/launchpad.py: -------------------------------------------------------------------------------- 1 | """ 2 | Launchpad OpenId backend 3 | """ 4 | 5 | from .open_id import OpenIdAuth 6 | 7 | 8 | class LaunchpadOpenId(OpenIdAuth): 9 | name = 'launchpad' 10 | URL = 'https://login.launchpad.net' 11 | USERNAME_KEY = 'nickname' 12 | -------------------------------------------------------------------------------- /social_core/backends/legacy.py: -------------------------------------------------------------------------------- 1 | from .base import BaseAuth 2 | from ..exceptions import AuthMissingParameter 3 | 4 | 5 | class LegacyAuth(BaseAuth): 6 | def get_user_id(self, details, response): 7 | return details.get(self.ID_KEY) or \ 8 | response.get(self.ID_KEY) 9 | 10 | def auth_url(self): 11 | return self.setting('FORM_URL') 12 | 13 | def auth_html(self): 14 | return self.strategy.render_html(tpl=self.setting('FORM_HTML')) 15 | 16 | def uses_redirect(self): 17 | return self.setting('FORM_URL') and not \ 18 | self.setting('FORM_HTML') 19 | 20 | def auth_complete(self, *args, **kwargs): 21 | """Completes login process, must return user instance""" 22 | if self.ID_KEY not in self.data: 23 | raise AuthMissingParameter(self, self.ID_KEY) 24 | kwargs.update({'response': self.data, 'backend': self}) 25 | return self.strategy.authenticate(*args, **kwargs) 26 | 27 | def get_user_details(self, response): 28 | """Return user details""" 29 | email = response.get('email', '') 30 | username = response.get('username', '') 31 | fullname, first_name, last_name = self.get_user_names( 32 | response.get('fullname', ''), 33 | response.get('first_name', ''), 34 | response.get('last_name', '') 35 | ) 36 | if email and not username: 37 | username = email.split('@', 1)[0] 38 | return { 39 | 'username': username, 40 | 'email': email, 41 | 'fullname': fullname, 42 | 'first_name': first_name, 43 | 'last_name': last_name 44 | } 45 | -------------------------------------------------------------------------------- /social_core/backends/live.py: -------------------------------------------------------------------------------- 1 | """ 2 | Live OAuth2 backend, docs at: 3 | https://python-social-auth.readthedocs.io/en/latest/backends/live.html 4 | """ 5 | from .oauth import BaseOAuth2 6 | 7 | 8 | class LiveOAuth2(BaseOAuth2): 9 | name = 'live' 10 | AUTHORIZATION_URL = 'https://login.live.com/oauth20_authorize.srf' 11 | ACCESS_TOKEN_URL = 'https://login.live.com/oauth20_token.srf' 12 | ACCESS_TOKEN_METHOD = 'POST' 13 | SCOPE_SEPARATOR = ',' 14 | DEFAULT_SCOPE = ['wl.basic', 'wl.emails'] 15 | EXTRA_DATA = [ 16 | ('id', 'id'), 17 | ('access_token', 'access_token'), 18 | ('authentication_token', 'authentication_token'), 19 | ('refresh_token', 'refresh_token'), 20 | ('expires_in', 'expires'), 21 | ('email', 'email'), 22 | ('first_name', 'first_name'), 23 | ('last_name', 'last_name'), 24 | ('token_type', 'token_type'), 25 | ] 26 | REDIRECT_STATE = False 27 | 28 | def get_user_details(self, response): 29 | """Return user details from Live Connect account""" 30 | fullname, first_name, last_name = self.get_user_names( 31 | first_name=response.get('first_name'), 32 | last_name=response.get('last_name') 33 | ) 34 | return {'username': response.get('name'), 35 | 'email': response.get('emails', {}).get('account', ''), 36 | 'fullname': fullname, 37 | 'first_name': first_name, 38 | 'last_name': last_name} 39 | 40 | def user_data(self, access_token, *args, **kwargs): 41 | """Loads user data from service""" 42 | return self.get_json('https://apis.live.net/v5.0/me', params={ 43 | 'access_token': access_token 44 | }) 45 | -------------------------------------------------------------------------------- /social_core/backends/livejournal.py: -------------------------------------------------------------------------------- 1 | """ 2 | LiveJournal OpenId backend, docs at: 3 | https://python-social-auth.readthedocs.io/en/latest/backends/livejournal.html 4 | """ 5 | from six.moves.urllib_parse import urlsplit 6 | 7 | from .open_id import OpenIdAuth 8 | from ..exceptions import AuthMissingParameter 9 | 10 | 11 | class LiveJournalOpenId(OpenIdAuth): 12 | """LiveJournal OpenID authentication backend""" 13 | name = 'livejournal' 14 | 15 | def get_user_details(self, response): 16 | """Generate username from identity url""" 17 | values = super(LiveJournalOpenId, self).get_user_details(response) 18 | values['username'] = values.get('username') or \ 19 | urlsplit(response.identity_url)\ 20 | .netloc.split('.', 1)[0] 21 | return values 22 | 23 | def openid_url(self): 24 | """Returns LiveJournal authentication URL""" 25 | if not self.data.get('openid_lj_user'): 26 | raise AuthMissingParameter(self, 'openid_lj_user') 27 | return 'http://{0}.livejournal.com'.format(self.data['openid_lj_user']) 28 | -------------------------------------------------------------------------------- /social_core/backends/mailchimp.py: -------------------------------------------------------------------------------- 1 | from .oauth import BaseOAuth2 2 | 3 | 4 | class MailChimpOAuth2(BaseOAuth2): 5 | """MailChimp OAuth2 authentication backend""" 6 | name = 'mailchimp' 7 | AUTHORIZATION_URL = 'https://login.mailchimp.com/oauth2/authorize' 8 | ACCESS_TOKEN_URL = 'https://login.mailchimp.com/oauth2/token' 9 | METADATA_URL = 'https://login.mailchimp.com/oauth2/metadata' 10 | ACCESS_TOKEN_METHOD = 'POST' 11 | STATE_PARAMETER = False 12 | REDIRECT_STATE = False 13 | ID_KEY = 'user_id' 14 | EXTRA_DATA = [ 15 | ('accountname', 'accountname'), 16 | ('api_endpoint', 'api_endpoint'), 17 | ('role', 'role'), 18 | ('login', 'login') 19 | ] 20 | 21 | def get_user_details(self, response): 22 | """Return user details from a Mailchimp metadata response""" 23 | return { 24 | 'username': response['login']['login_name'], 25 | 'email': response['login']['email'] 26 | } 27 | 28 | def user_data(self, access_token, *args, **kwargs): 29 | """Loads user data and datacenter information from service""" 30 | return self.get_json(self.METADATA_URL, headers={ 31 | 'Authorization': 'OAuth ' + access_token 32 | }) 33 | -------------------------------------------------------------------------------- /social_core/backends/mapmyfitness.py: -------------------------------------------------------------------------------- 1 | """ 2 | MapMyFitness OAuth2 backend, docs at: 3 | https://python-social-auth.readthedocs.io/en/latest/backends/mapmyfitness.html 4 | """ 5 | from .oauth import BaseOAuth2 6 | 7 | 8 | class MapMyFitnessOAuth2(BaseOAuth2): 9 | """MapMyFitness OAuth authentication backend""" 10 | name = 'mapmyfitness' 11 | AUTHORIZATION_URL = 'https://www.mapmyfitness.com/v7.0/oauth2/authorize' 12 | ACCESS_TOKEN_URL = \ 13 | 'https://oauth2-api.mapmyapi.com/v7.0/oauth2/access_token' 14 | REQUEST_TOKEN_METHOD = 'POST' 15 | ACCESS_TOKEN_METHOD = 'POST' 16 | REDIRECT_STATE = False 17 | EXTRA_DATA = [ 18 | ('refresh_token', 'refresh_token'), 19 | ] 20 | 21 | def auth_headers(self): 22 | key = self.get_key_and_secret()[0] 23 | return { 24 | 'Api-Key': key 25 | } 26 | 27 | def get_user_id(self, details, response): 28 | return response['id'] 29 | 30 | def get_user_details(self, response): 31 | first = response.get('first_name', '') 32 | last = response.get('last_name', '') 33 | full = (first + last).strip() 34 | return { 35 | 'username': response['username'], 36 | 'email': response['email'], 37 | 'fullname': full, 38 | 'first_name': first, 39 | 'last_name': last, 40 | } 41 | 42 | def user_data(self, access_token, *args, **kwargs): 43 | key = self.get_key_and_secret()[0] 44 | url = 'https://oauth2-api.mapmyapi.com/v7.0/user/self/' 45 | headers = { 46 | 'Authorization': 'Bearer {0}'.format(access_token), 47 | 'Api-Key': key 48 | } 49 | return self.get_json(url, headers=headers) 50 | -------------------------------------------------------------------------------- /social_core/backends/meetup.py: -------------------------------------------------------------------------------- 1 | """ 2 | Meetup OAuth2 backend, docs at: 3 | https://python-social-auth.readthedocs.io/en/latest/backends/meetup.html 4 | """ 5 | from .oauth import BaseOAuth2 6 | 7 | 8 | class MeetupOAuth2(BaseOAuth2): 9 | """Meetup OAuth2 authentication backend""" 10 | name = 'meetup' 11 | AUTHORIZATION_URL = 'https://secure.meetup.com/oauth2/authorize' 12 | ACCESS_TOKEN_URL = 'https://secure.meetup.com/oauth2/access' 13 | ACCESS_TOKEN_METHOD = 'POST' 14 | DEFAULT_SCOPE = ['basic'] 15 | SCOPE_SEPARATOR = ',' 16 | REDIRECT_STATE = False 17 | STATE_PARAMETER = 'state' 18 | 19 | def get_user_details(self, response): 20 | """Return user details from Meetup account""" 21 | fullname, first_name, last_name = self.get_user_names( 22 | response.get('name') 23 | ) 24 | 25 | return {'username': response.get('username'), 26 | 'email': response.get('email') or '', 27 | 'fullname': fullname, 28 | 'first_name': first_name, 29 | 'last_name': last_name} 30 | 31 | def user_data(self, access_token, *args, **kwargs): 32 | """Loads user data from service""" 33 | return self.get_json('https://api.meetup.com/2/member/self', 34 | params={'access_token': access_token}) 35 | -------------------------------------------------------------------------------- /social_core/backends/mineid.py: -------------------------------------------------------------------------------- 1 | from .oauth import BaseOAuth2 2 | 3 | 4 | class MineIDOAuth2(BaseOAuth2): 5 | """MineID OAuth2 authentication backend""" 6 | name = 'mineid' 7 | _AUTHORIZATION_URL = '%(scheme)s://%(host)s/oauth/authorize' 8 | _ACCESS_TOKEN_URL = '%(scheme)s://%(host)s/oauth/access_token' 9 | ACCESS_TOKEN_METHOD = 'POST' 10 | SCOPE_SEPARATOR = ',' 11 | EXTRA_DATA = [ 12 | ] 13 | 14 | def get_user_details(self, response): 15 | """Return user details""" 16 | return {'email': response.get('email'), 17 | 'username': response.get('email')} 18 | 19 | def user_data(self, access_token, *args, **kwargs): 20 | return self._user_data(access_token) 21 | 22 | def _user_data(self, access_token, path=None): 23 | url = '%(scheme)s://%(host)s/api/user' % self.get_mineid_url_params() 24 | return self.get_json(url, params={'access_token': access_token}) 25 | 26 | @property 27 | def AUTHORIZATION_URL(self): 28 | return self._AUTHORIZATION_URL % self.get_mineid_url_params() 29 | 30 | @property 31 | def ACCESS_TOKEN_URL(self): 32 | return self._ACCESS_TOKEN_URL % self.get_mineid_url_params() 33 | 34 | def get_mineid_url_params(self): 35 | return { 36 | 'host': self.setting('HOST', 'www.mineid.org'), 37 | 'scheme': self.setting('SCHEME', 'https'), 38 | } 39 | -------------------------------------------------------------------------------- /social_core/backends/mixcloud.py: -------------------------------------------------------------------------------- 1 | """ 2 | Mixcloud OAuth2 backend, docs at: 3 | https://python-social-auth.readthedocs.io/en/latest/backends/mixcloud.html 4 | """ 5 | from .oauth import BaseOAuth2 6 | 7 | 8 | class MixcloudOAuth2(BaseOAuth2): 9 | name = 'mixcloud' 10 | ID_KEY = 'username' 11 | AUTHORIZATION_URL = 'https://www.mixcloud.com/oauth/authorize' 12 | ACCESS_TOKEN_URL = 'https://www.mixcloud.com/oauth/access_token' 13 | ACCESS_TOKEN_METHOD = 'POST' 14 | 15 | def get_user_details(self, response): 16 | fullname, first_name, last_name = self.get_user_names(response['name']) 17 | return {'username': response['username'], 18 | 'email': None, 19 | 'fullname': fullname, 20 | 'first_name': first_name, 21 | 'last_name': last_name} 22 | 23 | def user_data(self, access_token, *args, **kwargs): 24 | return self.get_json('https://api.mixcloud.com/me/', 25 | params={'access_token': access_token, 26 | 'alt': 'json'}) 27 | -------------------------------------------------------------------------------- /social_core/backends/monzo.py: -------------------------------------------------------------------------------- 1 | from .oauth import BaseOAuth2 2 | 3 | 4 | class MonzoOAuth2(BaseOAuth2): 5 | """ 6 | Monzo OAuth2 authentication backend. 7 | """ 8 | 9 | name = 'monzo' 10 | 11 | AUTHORIZATION_URL = 'https://auth.getmondo.co.uk/' 12 | ACCESS_TOKEN_URL = 'https://api.monzo.com/oauth2/token' 13 | ACCESS_TOKEN_METHOD = 'POST' 14 | REDIRECT_STATE = False 15 | 16 | def get_user_details(self, response): 17 | fullname, first_name, last_name = self.get_user_names( 18 | response['accounts'][0]['description'], 19 | ) 20 | 21 | return { 22 | 'username': str(response.get('user_id')), 23 | 'fullname': fullname, 24 | 'first_name': first_name, 25 | 'last_name': last_name, 26 | } 27 | 28 | def user_data(self, access_token, *args, **kwargs): 29 | return self.get_json( 30 | 'https://api.monzo.com/accounts', 31 | headers={'Authorization': 'Bearer {0}'.format(access_token)}, 32 | ) 33 | -------------------------------------------------------------------------------- /social_core/backends/moves.py: -------------------------------------------------------------------------------- 1 | """ 2 | Moves OAuth2 backend, docs at: 3 | https://dev.moves-app.com/docs/authentication 4 | 5 | Written by Avi Alkalay 6 | Certified to work with Django 1.6 7 | """ 8 | from .oauth import BaseOAuth2 9 | 10 | 11 | class MovesOAuth2(BaseOAuth2): 12 | """Moves OAuth authentication backend""" 13 | name = 'moves' 14 | ID_KEY = 'user_id' 15 | AUTHORIZATION_URL = 'https://api.moves-app.com/oauth/v1/authorize' 16 | ACCESS_TOKEN_URL = 'https://api.moves-app.com/oauth/v1/access_token' 17 | ACCESS_TOKEN_METHOD = 'POST' 18 | EXTRA_DATA = [ 19 | ('refresh_token', 'refresh_token', True), 20 | ('expires_in', 'expires'), 21 | ] 22 | 23 | def get_user_details(self, response): 24 | """Return user details Moves account""" 25 | return {'username': str(response.get('user_id'))} 26 | 27 | def user_data(self, access_token, *args, **kwargs): 28 | """Loads user data from service""" 29 | return self.get_json('https://api.moves-app.com/api/1.1/user/profile', 30 | params={'access_token': access_token}) 31 | -------------------------------------------------------------------------------- /social_core/backends/openshift.py: -------------------------------------------------------------------------------- 1 | """ 2 | Openshift OAuth2 backend 3 | """ 4 | import requests 5 | 6 | from six.moves.urllib.parse import urljoin 7 | 8 | from ..utils import append_slash 9 | from .oauth import BaseOAuth2 10 | 11 | 12 | class OpenshiftOAuth2(BaseOAuth2): 13 | name = 'openshift' 14 | ACCESS_TOKEN_METHOD = 'POST' 15 | 16 | def access_token_url(self): 17 | return urljoin(append_slash(self.setting('URL')), 'oauth/token') 18 | 19 | def authorization_url(self): 20 | return urljoin(append_slash(self.setting('URL')), 'oauth/authorize') 21 | 22 | def get_user_id(self, details, response): 23 | return response['metadata']['uid'] 24 | 25 | def get_user_details(self, response): 26 | """Return user details from openshift account""" 27 | username = response['metadata']['name'] 28 | email = response['metadata']['name'] 29 | return {'username': username, 30 | 'email': email} 31 | 32 | def user_data(self, access_token, *args, **kwargs): 33 | """Loads user data from service""" 34 | headers = {'Authorization': 'Bearer ' + access_token} 35 | 36 | return requests.get( 37 | urljoin(append_slash(self.setting('URL')), 'oapi/v1/users/~'), 38 | headers=headers 39 | ).json() 40 | -------------------------------------------------------------------------------- /social_core/backends/orbi.py: -------------------------------------------------------------------------------- 1 | """ 2 | Orbi OAuth2 backend 3 | """ 4 | from .oauth import BaseOAuth2 5 | 6 | 7 | class OrbiOAuth2(BaseOAuth2): 8 | """Orbi OAuth2 authentication backend""" 9 | name = 'orbi' 10 | AUTHORIZATION_URL = 'https://login.orbi.kr/oauth/authorize' 11 | ACCESS_TOKEN_URL = 'https://login.orbi.kr/oauth/token' 12 | ACCESS_TOKEN_METHOD = 'POST' 13 | EXTRA_DATA = [ 14 | ('imin', 'imin'), 15 | ('nick', 'nick'), 16 | ('photo', 'photo'), 17 | ('sex', 'sex'), 18 | ('birth', 'birth'), 19 | ] 20 | 21 | def get_user_id(self, details, response): 22 | return response.get('id') 23 | 24 | def get_user_details(self, response): 25 | fullname, first_name, last_name = self.get_user_names( 26 | response.get('name', ''), 27 | response.get('first_name', ''), 28 | response.get('last_name', '') 29 | ) 30 | return { 31 | 'username': response.get('username', response.get('name')), 32 | 'email': response.get('email', ''), 33 | 'fullname': fullname, 34 | 'first_name': first_name, 35 | 'last_name': last_name, 36 | } 37 | 38 | def user_data(self, access_token, *args, **kwargs): 39 | """Load user data from orbi""" 40 | return self.get_json('https://login.orbi.kr/oauth/user/get', params={ 41 | 'access_token': access_token 42 | }) 43 | -------------------------------------------------------------------------------- /social_core/backends/patreon.py: -------------------------------------------------------------------------------- 1 | """ 2 | Patreon OAuth2 backend 3 | https://www.patreon.com/platform/documentation/oauth 4 | """ 5 | from .oauth import BaseOAuth2 6 | 7 | 8 | class PatreonOAuth2(BaseOAuth2): 9 | """Patreon OAuth2 authentication backend""" 10 | name = 'patreon' 11 | AUTHORIZATION_URL = 'https://www.patreon.com/oauth2/authorize' 12 | ACCESS_TOKEN_URL = 'https://api.patreon.com/oauth2/token' 13 | REVOKE_TOKEN_URL = 'https://api.patreon.com/oauth2/revoke' 14 | ACCESS_TOKEN_METHOD = 'POST' 15 | REDIRECT_STATE = False 16 | ID_KEY = 'id' 17 | EXTRA_DATA = [ 18 | ('id', 'id'), 19 | ] 20 | 21 | def get_user_details(self, response): 22 | details = response['attributes'] 23 | return { 24 | 'username': details.get('full_name'), 25 | 'email': details.get('email'), 26 | 'fullname': details.get('full_name'), 27 | 'first_name': details.get('first_name'), 28 | 'last_name': details.get('last_name'), 29 | } 30 | 31 | def user_data(self, access_token, *args, **kwargs): 32 | return self.get_api(access_token, 'current_user')['data'] 33 | 34 | def get_api(self, access_token, suffix): 35 | return self.get_json( 36 | 'https://api.patreon.com/oauth2/api/{}'.format(suffix), 37 | headers=self.get_auth_header(access_token) 38 | ) 39 | 40 | def get_auth_header(self, access_token): 41 | return {'Authorization': 'Bearer {0}'.format(access_token)} 42 | -------------------------------------------------------------------------------- /social_core/backends/phabricator.py: -------------------------------------------------------------------------------- 1 | """ 2 | Phabricator OAuth2 backend, docs at: 3 | https://secure.phabricator.com/book/phabcontrib/article/using_oauthserver/ 4 | """ 5 | from .oauth import BaseOAuth2 6 | 7 | 8 | class PhabricatorOAuth2(BaseOAuth2): 9 | """Phabricator OAuth authentication backend""" 10 | name = 'phabricator' 11 | API_URL = 'https://secure.phabricator.com' 12 | AUTHORIZATION_URL = 'https://secure.phabricator.com/oauthserver/auth/' 13 | ACCESS_TOKEN_URL = 'https://secure.phabricator.com/oauthserver/token/' 14 | ACCESS_TOKEN_METHOD = 'POST' 15 | REDIRECT_STATE = False 16 | 17 | def api_url(self, path): 18 | api_url = self.setting('API_URL') or self.API_URL 19 | return '{0}{1}'.format(api_url.rstrip('/'), path) 20 | 21 | def authorization_url(self): 22 | return self.api_url('/oauthserver/auth/') 23 | 24 | def access_token_url(self): 25 | return self.api_url('/oauthserver/token/') 26 | 27 | def get_user_details(self, response): 28 | """Return user details from Phabricator""" 29 | fullname, first_name, last_name = self.get_user_names( 30 | response.get('realName') 31 | ) 32 | 33 | return { 34 | 'id': response.get('phid'), 35 | 'username': response.get('userName'), 36 | 'email': response.get('primaryEmail', ''), 37 | 'fullname': fullname, 38 | 'first_name': first_name, 39 | 'last_name': last_name, 40 | } 41 | 42 | def user_data(self, access_token, *args, **kwargs): 43 | """Loads user data from API""" 44 | return self.get_json(self.api_url('/api/user.whoami'), params={ 45 | 'access_token': access_token, 46 | }) 47 | -------------------------------------------------------------------------------- /social_core/backends/pinterest.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Pinterest OAuth2 backend, docs at: 4 | https://developers.pinterest.com/docs/api/authentication/ 5 | """ 6 | 7 | from __future__ import unicode_literals 8 | 9 | import ssl 10 | 11 | from .oauth import BaseOAuth2 12 | 13 | 14 | class PinterestOAuth2(BaseOAuth2): 15 | name = 'pinterest' 16 | ID_KEY = 'user_id' 17 | AUTHORIZATION_URL = 'https://api.pinterest.com/oauth/' 18 | ACCESS_TOKEN_URL = 'https://api.pinterest.com/v1/oauth/token' 19 | REDIRECT_STATE = False 20 | ACCESS_TOKEN_METHOD = 'POST' 21 | SSL_PROTOCOL = ssl.PROTOCOL_TLSv1 22 | 23 | def user_data(self, access_token, *args, **kwargs): 24 | response = self.get_json('https://api.pinterest.com/v1/me/', 25 | params={'access_token': access_token}) 26 | 27 | if 'data' in response: 28 | username = response['data']['url'].strip('/').split('/')[-1] 29 | response = { 30 | 'user_id': response['data']['id'], 31 | 'first_name': response['data']['first_name'], 32 | 'last_name': response['data']['last_name'], 33 | 'username': username, 34 | } 35 | return response 36 | 37 | def get_user_details(self, response): 38 | fullname, first_name, last_name = self.get_user_names( 39 | first_name=response['first_name'], 40 | last_name=response['last_name']) 41 | 42 | return {'username': response.get('username'), 43 | 'email': None, 44 | 'fullname': fullname, 45 | 'first_name': first_name, 46 | 'last_name': last_name} 47 | -------------------------------------------------------------------------------- /social_core/backends/pixelpin.py: -------------------------------------------------------------------------------- 1 | import json 2 | from .open_id_connect import OpenIdConnectAuth 3 | 4 | 5 | class PixelPinOpenIDConnect(OpenIdConnectAuth): 6 | """PixelPin OpenID Connect authentication backend""" 7 | name = 'pixelpin-openidconnect' 8 | ID_KEY = 'sub' 9 | AUTHORIZATION_URL = 'https://login.pixelpin.io/connect/authorize' 10 | ACCESS_TOKEN_URL = 'https://login.pixelpin.io/connect/token' 11 | OIDC_ENDPOINT = 'https://login.pixelpin.io' 12 | JWKS_URI = 'https://login.pixelpin.io/.well-known/jwks' 13 | ACCESS_TOKEN_METHOD = 'POST' 14 | REQUIRES_EMAIL_VALIDATION = False 15 | 16 | def get_user_details(self, response): 17 | """Return user details from PixelPin account""" 18 | first_name = response.get('given_name') 19 | last_name = response.get('family_name') 20 | sub = response.get('sub') 21 | 22 | username = first_name + last_name + sub 23 | 24 | return {'username': username, 25 | 'email': response.get('email'), 26 | 'fullname': first_name + ' ' + last_name, 27 | 'first_name': first_name, 28 | 'last_name': last_name} 29 | 30 | def user_data(self, access_token, *args, **kwargs): 31 | return self.get_json( 32 | 'https://login.pixelpin.io/connect/userinfo', 33 | headers={ 34 | 'Authorization': 'Bearer {0}'.format(access_token) 35 | } 36 | ) 37 | -------------------------------------------------------------------------------- /social_core/backends/podio.py: -------------------------------------------------------------------------------- 1 | """ 2 | Podio OAuth2 backend, docs at: 3 | https://python-social-auth.readthedocs.io/en/latest/backends/podio.html 4 | """ 5 | from .oauth import BaseOAuth2 6 | 7 | 8 | class PodioOAuth2(BaseOAuth2): 9 | """Podio OAuth authentication backend""" 10 | name = 'podio' 11 | AUTHORIZATION_URL = 'https://podio.com/oauth/authorize' 12 | ACCESS_TOKEN_URL = 'https://podio.com/oauth/token' 13 | ACCESS_TOKEN_METHOD = 'POST' 14 | EXTRA_DATA = [ 15 | ('access_token', 'access_token'), 16 | ('token_type', 'token_type'), 17 | ('expires_in', 'expires'), 18 | ('refresh_token', 'refresh_token'), 19 | ] 20 | 21 | def get_user_id(self, details, response): 22 | return response['ref']['id'] 23 | 24 | def get_user_details(self, response): 25 | fullname, first_name, last_name = self.get_user_names( 26 | response['profile']['name'] 27 | ) 28 | return { 29 | 'username': 'user_%d' % response['user']['user_id'], 30 | 'email': response['user']['mail'], 31 | 'fullname': fullname, 32 | 'first_name': first_name, 33 | 'last_name': last_name, 34 | } 35 | 36 | def user_data(self, access_token, *args, **kwargs): 37 | return self.get_json('https://api.podio.com/user/status', 38 | headers={'Authorization': 'OAuth2 ' + access_token}) 39 | -------------------------------------------------------------------------------- /social_core/backends/pushbullet.py: -------------------------------------------------------------------------------- 1 | import base64 2 | 3 | from .oauth import BaseOAuth2 4 | 5 | 6 | class PushbulletOAuth2(BaseOAuth2): 7 | """pushbullet OAuth authentication backend""" 8 | name = 'pushbullet' 9 | EXTRA_DATA = [('id', 'id')] 10 | ID_KEY = 'username' 11 | AUTHORIZATION_URL = 'https://www.pushbullet.com/authorize' 12 | REQUEST_TOKEN_URL = 'https://api.pushbullet.com/oauth2/token' 13 | ACCESS_TOKEN_URL = 'https://api.pushbullet.com/oauth2/token' 14 | ACCESS_TOKEN_METHOD = 'POST' 15 | STATE_PARAMETER = False 16 | 17 | def get_user_details(self, response): 18 | return {'username': response.get('access_token')} 19 | 20 | def get_user_id(self, details, response): 21 | auth = 'Basic {0}'.format(base64.b64encode(details['username'])) 22 | return self.get_json('https://api.pushbullet.com/v2/users/me', 23 | headers={'Authorization': auth})['iden'] 24 | -------------------------------------------------------------------------------- /social_core/backends/quizlet.py: -------------------------------------------------------------------------------- 1 | """ 2 | Quizlet OAuth2 Sign-in backend, docs at: 3 | https://python-social-auth.readthedocs.io/en/latest/backends/quizlet.html 4 | """ 5 | from .oauth import BaseOAuth2 6 | 7 | 8 | class QuizletOAuth2(BaseOAuth2): 9 | """Quizlet OAuth2""" 10 | name = 'quizlet' 11 | ID_KEY = 'user_id' 12 | API_URL = 'https://api.quizlet.com/2.0/' 13 | AUTHORIZATION_URL = 'https://quizlet.com/authorize' 14 | ACCESS_TOKEN_URL = 'https://api.quizlet.com/oauth/token' 15 | ACCESS_TOKEN_METHOD = 'POST' 16 | SCOPE_SEPARATOR = ' ' 17 | DEFAULT_SCOPE = ['read'] 18 | 19 | def get_user_details(self, response): 20 | """Return user details from Quizlet account""" 21 | return { 22 | 'username': response.get('user_id') 23 | } 24 | -------------------------------------------------------------------------------- /social_core/backends/readability.py: -------------------------------------------------------------------------------- 1 | """ 2 | Readability OAuth1 backend, docs at: 3 | https://python-social-auth.readthedocs.io/en/latest/backends/readability.html 4 | """ 5 | from .oauth import BaseOAuth1 6 | 7 | 8 | READABILITY_API = 'https://www.readability.com/api/rest/v1' 9 | 10 | 11 | class ReadabilityOAuth(BaseOAuth1): 12 | """Readability OAuth authentication backend""" 13 | name = 'readability' 14 | ID_KEY = 'username' 15 | AUTHORIZATION_URL = '{0}/oauth/authorize/'.format(READABILITY_API) 16 | REQUEST_TOKEN_URL = '{0}/oauth/request_token/'.format(READABILITY_API) 17 | ACCESS_TOKEN_URL = '{0}/oauth/access_token/'.format(READABILITY_API) 18 | EXTRA_DATA = [('date_joined', 'date_joined'), 19 | ('kindle_email_address', 'kindle_email_address'), 20 | ('avatar_url', 'avatar_url'), 21 | ('email_into_address', 'email_into_address')] 22 | 23 | def get_user_details(self, response): 24 | fullname, first_name, last_name = self.get_user_names( 25 | first_name=response['first_name'], 26 | last_name=response['last_name'] 27 | ) 28 | return {'username': response['username'], 29 | 'fullname': fullname, 30 | 'first_name': first_name, 31 | 'last_name': last_name} 32 | 33 | def user_data(self, access_token): 34 | return self.get_json(READABILITY_API + '/users/_current', 35 | auth=self.oauth_auth(access_token)) 36 | -------------------------------------------------------------------------------- /social_core/backends/shimmering.py: -------------------------------------------------------------------------------- 1 | """ 2 | Shimmering Oauth 3 | """ 4 | from .oauth import BaseOAuth2 5 | 6 | 7 | class ShimmeringOAuth2(BaseOAuth2): 8 | """Shimmering Verify OAuth2 authentication backend""" 9 | name = 'shimmering' 10 | ID_KEY = 'id' 11 | AUTHORIZATION_URL = 'http://developers.shimmeringverify.com/o/authorize/' 12 | ACCESS_TOKEN_URL = 'http://developers.shimmeringverify.com/o/token/' 13 | ACCESS_TOKEN_METHOD = 'POST' 14 | 15 | def get_user_details(self, response): 16 | """Return user details from Shimmering""" 17 | first_name = response.get('first_name') 18 | last_name = response.get('last_name') 19 | email = response.get('email') 20 | username = response.get('username') 21 | fullname = '{} {}'.format(first_name, last_name) 22 | return { 23 | 'username': username, 24 | 'fullname': fullname, 25 | 'first_name': first_name, 26 | 'last_name': last_name, 27 | 'email': email, 28 | } 29 | 30 | def user_data(self, access_token, *args, **kwargs): 31 | """Loads user data from service""" 32 | headers = {'Authorization': 'Bearer %s' % access_token} 33 | return self.get_json( 34 | 'http://developers.shimmeringverify.com/user_info/', 35 | headers=headers 36 | ) 37 | -------------------------------------------------------------------------------- /social_core/backends/sketchfab.py: -------------------------------------------------------------------------------- 1 | """ 2 | Sketchfab OAuth2 backend, docs at: 3 | https://python-social-auth.readthedocs.io/en/latest/backends/sketchfab.html 4 | https://sketchfab.com/developers/oauth 5 | """ 6 | from .oauth import BaseOAuth2 7 | 8 | 9 | class SketchfabOAuth2(BaseOAuth2): 10 | name = 'sketchfab' 11 | ID_KEY = 'uid' 12 | AUTHORIZATION_URL = 'https://sketchfab.com/oauth2/authorize/' 13 | ACCESS_TOKEN_URL = 'https://sketchfab.com/oauth2/token/' 14 | ACCESS_TOKEN_METHOD = 'POST' 15 | REDIRECT_STATE = False 16 | REQUIRES_EMAIL_VALIDATION = False 17 | EXTRA_DATA = [ 18 | ('username', 'username'), 19 | ('apiToken', 'apiToken') 20 | ] 21 | 22 | def get_user_details(self, response): 23 | """Return user details from Sketchfab account""" 24 | user_data = response 25 | email = user_data.get('email', '') 26 | username = user_data['username'] 27 | name = user_data.get('displayName', '') 28 | fullname, first_name, last_name = self.get_user_names(name) 29 | return {'username': username, 30 | 'fullname': fullname, 31 | 'first_name': first_name, 32 | 'last_name': last_name, 33 | 'email': email} 34 | 35 | def user_data(self, access_token, *args, **kwargs): 36 | """Loads user data from service""" 37 | return self.get_json('https://sketchfab.com/v2/users/me', headers={ 38 | 'Authorization': 'Bearer {0}'.format(access_token) 39 | }) 40 | -------------------------------------------------------------------------------- /social_core/backends/skyrock.py: -------------------------------------------------------------------------------- 1 | """ 2 | Skyrock OAuth1 backend, docs at: 3 | https://python-social-auth.readthedocs.io/en/latest/backends/skyrock.html 4 | """ 5 | from .oauth import BaseOAuth1 6 | 7 | 8 | class SkyrockOAuth(BaseOAuth1): 9 | """Skyrock OAuth authentication backend""" 10 | name = 'skyrock' 11 | ID_KEY = 'id_user' 12 | AUTHORIZATION_URL = 'https://api.skyrock.com/v2/oauth/authenticate' 13 | REQUEST_TOKEN_URL = 'https://api.skyrock.com/v2/oauth/initiate' 14 | ACCESS_TOKEN_URL = 'https://api.skyrock.com/v2/oauth/token' 15 | EXTRA_DATA = [('id', 'id')] 16 | 17 | def get_user_details(self, response): 18 | """Return user details from Skyrock account""" 19 | fullname, first_name, last_name = self.get_user_names( 20 | first_name=response['firstname'], 21 | last_name=response['name'] 22 | ) 23 | return {'username': response['username'], 24 | 'email': response['email'], 25 | 'fullname': fullname, 26 | 'first_name': first_name, 27 | 'last_name': last_name} 28 | 29 | def user_data(self, access_token): 30 | """Return user data provided""" 31 | return self.get_json('https://api.skyrock.com/v2/user/get.json', 32 | auth=self.oauth_auth(access_token)) 33 | -------------------------------------------------------------------------------- /social_core/backends/spotify.py: -------------------------------------------------------------------------------- 1 | """ 2 | Spotify backend, docs at: 3 | https://developer.spotify.com/spotify-web-api/ 4 | https://developer.spotify.com/spotify-web-api/authorization-guide/ 5 | """ 6 | import base64 7 | 8 | from .oauth import BaseOAuth2 9 | 10 | 11 | class SpotifyOAuth2(BaseOAuth2): 12 | """Spotify OAuth2 authentication backend""" 13 | name = 'spotify' 14 | ID_KEY = 'id' 15 | AUTHORIZATION_URL = 'https://accounts.spotify.com/authorize' 16 | ACCESS_TOKEN_URL = 'https://accounts.spotify.com/api/token' 17 | ACCESS_TOKEN_METHOD = 'POST' 18 | SCOPE_SEPARATOR = ' ' 19 | REDIRECT_STATE = False 20 | EXTRA_DATA = [ 21 | ('refresh_token', 'refresh_token'), 22 | ] 23 | 24 | def auth_headers(self): 25 | auth_str = '{0}:{1}'.format(*self.get_key_and_secret()) 26 | b64_auth_str = base64.urlsafe_b64encode(auth_str.encode()).decode() 27 | return { 28 | 'Authorization': 'Basic {0}'.format(b64_auth_str) 29 | } 30 | 31 | def get_user_details(self, response): 32 | """Return user details from Spotify account""" 33 | fullname, first_name, last_name = self.get_user_names( 34 | response.get('display_name') 35 | ) 36 | return {'username': response.get('id'), 37 | 'email': response.get('email'), 38 | 'fullname': fullname, 39 | 'first_name': first_name, 40 | 'last_name': last_name} 41 | 42 | def user_data(self, access_token, *args, **kwargs): 43 | """Loads user data from service""" 44 | return self.get_json( 45 | 'https://api.spotify.com/v1/me', 46 | headers={'Authorization': 'Bearer {0}'.format(access_token)} 47 | ) 48 | -------------------------------------------------------------------------------- /social_core/backends/stackoverflow.py: -------------------------------------------------------------------------------- 1 | """ 2 | Stackoverflow OAuth2 backend, docs at: 3 | https://python-social-auth.readthedocs.io/en/latest/backends/stackoverflow.html 4 | """ 5 | from .oauth import BaseOAuth2 6 | 7 | 8 | class StackoverflowOAuth2(BaseOAuth2): 9 | """Stackoverflow OAuth2 authentication backend""" 10 | name = 'stackoverflow' 11 | ID_KEY = 'user_id' 12 | AUTHORIZATION_URL = 'https://stackexchange.com/oauth' 13 | ACCESS_TOKEN_URL = 'https://stackexchange.com/oauth/access_token' 14 | ACCESS_TOKEN_METHOD = 'POST' 15 | SCOPE_SEPARATOR = ',' 16 | EXTRA_DATA = [ 17 | ('id', 'id'), 18 | ('expires', 'expires') 19 | ] 20 | 21 | def get_user_details(self, response): 22 | """Return user details from Stackoverflow account""" 23 | fullname, first_name, last_name = self.get_user_names( 24 | response.get('display_name') 25 | ) 26 | return {'username': response.get('link').rsplit('/', 1)[-1], 27 | 'full_name': fullname, 28 | 'first_name': first_name, 29 | 'last_name': last_name} 30 | 31 | def user_data(self, access_token, *args, **kwargs): 32 | """Loads user data from service""" 33 | return self.get_json( 34 | 'https://api.stackexchange.com/2.1/me', 35 | params={ 36 | 'site': 'stackoverflow', 37 | 'access_token': access_token, 38 | 'key': self.setting('API_KEY') 39 | } 40 | )['items'][0] 41 | 42 | def request_access_token(self, *args, **kwargs): 43 | return self.get_querystring(*args, **kwargs) 44 | -------------------------------------------------------------------------------- /social_core/backends/steam.py: -------------------------------------------------------------------------------- 1 | """ 2 | Steam OpenId backend, docs at: 3 | https://python-social-auth.readthedocs.io/en/latest/backends/steam.html 4 | """ 5 | from .open_id import OpenIdAuth 6 | from ..exceptions import AuthFailed 7 | 8 | 9 | USER_INFO = 'http://api.steampowered.com/ISteamUser/GetPlayerSummaries/v0002/?' 10 | 11 | 12 | class SteamOpenId(OpenIdAuth): 13 | name = 'steam' 14 | URL = 'https://steamcommunity.com/openid' 15 | 16 | def get_user_id(self, details, response): 17 | """Return user unique id provided by service""" 18 | return self._user_id(response) 19 | 20 | def get_user_details(self, response): 21 | player = self.get_json(USER_INFO, params={ 22 | 'key': self.setting('API_KEY'), 23 | 'steamids': self._user_id(response) 24 | }) 25 | if len(player['response']['players']) > 0: 26 | player = player['response']['players'][0] 27 | details = {'username': player.get('personaname'), 28 | 'email': '', 29 | 'fullname': '', 30 | 'first_name': '', 31 | 'last_name': '', 32 | 'player': player} 33 | else: 34 | details = {} 35 | return details 36 | 37 | def consumer(self): 38 | # Steam seems to support stateless mode only, ignore store 39 | if not hasattr(self, '_consumer'): 40 | self._consumer = self.create_consumer() 41 | return self._consumer 42 | 43 | def _user_id(self, response): 44 | user_id = response.identity_url.rsplit('/', 1)[-1] 45 | if not user_id.isdigit(): 46 | raise AuthFailed(self, 'Missing Steam Id') 47 | return user_id 48 | -------------------------------------------------------------------------------- /social_core/backends/stocktwits.py: -------------------------------------------------------------------------------- 1 | """ 2 | Stocktwits OAuth2 backend, docs at: 3 | https://python-social-auth.readthedocs.io/en/latest/backends/stocktwits.html 4 | """ 5 | from .oauth import BaseOAuth2 6 | 7 | 8 | class StocktwitsOAuth2(BaseOAuth2): 9 | """Stockwiths OAuth2 backend""" 10 | name = 'stocktwits' 11 | AUTHORIZATION_URL = 'https://api.stocktwits.com/api/2/oauth/authorize' 12 | ACCESS_TOKEN_URL = 'https://api.stocktwits.com/api/2/oauth/token' 13 | ACCESS_TOKEN_METHOD = 'POST' 14 | SCOPE_SEPARATOR = ',' 15 | DEFAULT_SCOPE = ['read', 'publish_messages', 'publish_watch_lists', 16 | 'follow_users', 'follow_stocks'] 17 | 18 | def get_user_id(self, details, response): 19 | return response['user']['id'] 20 | 21 | def get_user_details(self, response): 22 | """Return user details from Stocktwits account""" 23 | fullname, first_name, last_name = self.get_user_names( 24 | response['user']['name'] 25 | ) 26 | return {'username': response['user']['username'], 27 | 'email': '', # not supplied 28 | 'fullname': fullname, 29 | 'first_name': first_name, 30 | 'last_name': last_name} 31 | 32 | def user_data(self, access_token, *args, **kwargs): 33 | """Loads user data from service""" 34 | return self.get_json( 35 | 'https://api.stocktwits.com/api/2/account/verify.json', 36 | params={'access_token': access_token} 37 | ) 38 | -------------------------------------------------------------------------------- /social_core/backends/suse.py: -------------------------------------------------------------------------------- 1 | """ 2 | Open Suse OpenId backend, docs at: 3 | https://python-social-auth.readthedocs.io/en/latest/backends/suse.html 4 | """ 5 | from .open_id import OpenIdAuth 6 | 7 | 8 | class OpenSUSEOpenId(OpenIdAuth): 9 | name = 'opensuse' 10 | URL = 'https://www.opensuse.org/openid/user/' 11 | 12 | def get_user_id(self, details, response): 13 | """ 14 | Return user unique id provided by service. For openSUSE 15 | the nickname is original. 16 | """ 17 | return details['nickname'] 18 | -------------------------------------------------------------------------------- /social_core/backends/taobao.py: -------------------------------------------------------------------------------- 1 | from .oauth import BaseOAuth2 2 | 3 | 4 | class TAOBAOAuth(BaseOAuth2): 5 | """Taobao OAuth authentication mechanism""" 6 | name = 'taobao' 7 | ID_KEY = 'taobao_user_id' 8 | ACCESS_TOKEN_METHOD = 'POST' 9 | AUTHORIZATION_URL = 'https://oauth.taobao.com/authorize' 10 | ACCESS_TOKEN_URL = 'https://oauth.taobao.com/token' 11 | 12 | def user_data(self, access_token, *args, **kwargs): 13 | """Return user data provided""" 14 | try: 15 | return self.get_json('https://eco.taobao.com/router/rest', params={ 16 | 'method': 'taobao.user.get', 17 | 'fomate': 'json', 18 | 'v': '2.0', 19 | 'access_token': access_token 20 | }) 21 | except ValueError: 22 | return None 23 | 24 | def get_user_details(self, response): 25 | """Return user details from Taobao account""" 26 | return {'username': response.get('taobao_user_nick')} 27 | -------------------------------------------------------------------------------- /social_core/backends/thisismyjam.py: -------------------------------------------------------------------------------- 1 | """ 2 | ThisIsMyJam OAuth1 backend, docs at: 3 | https://python-social-auth.readthedocs.io/en/latest/backends/thisismyjam.html 4 | """ 5 | from .oauth import BaseOAuth1 6 | 7 | 8 | class ThisIsMyJamOAuth1(BaseOAuth1): 9 | """ThisIsMyJam OAuth1 authentication backend""" 10 | name = 'thisismyjam' 11 | REQUEST_TOKEN_URL = 'http://www.thisismyjam.com/oauth/request_token' 12 | AUTHORIZATION_URL = 'http://www.thisismyjam.com/oauth/authorize' 13 | ACCESS_TOKEN_URL = 'http://www.thisismyjam.com/oauth/access_token' 14 | REDIRECT_URI_PARAMETER_NAME = 'oauth_callback' 15 | 16 | def get_user_details(self, response): 17 | """Return user details from ThisIsMyJam account""" 18 | info = response.get('person') 19 | fullname, first_name, last_name = self.get_user_names( 20 | info.get('fullname') 21 | ) 22 | return { 23 | 'username': info.get('name'), 24 | 'email': '', 25 | 'fullname': fullname, 26 | 'first_name': first_name, 27 | 'last_name': last_name 28 | } 29 | 30 | def user_data(self, access_token, *args, **kwargs): 31 | """Loads user data from service""" 32 | return self.get_json('http://api.thisismyjam.com/1/verify.json', 33 | auth=self.oauth_auth(access_token)) 34 | -------------------------------------------------------------------------------- /social_core/backends/trello.py: -------------------------------------------------------------------------------- 1 | """ 2 | Trello OAuth1 backend, docs at: 3 | https://python-social-auth.readthedocs.io/en/latest/backends/trello.html 4 | """ 5 | from .oauth import BaseOAuth1 6 | 7 | 8 | class TrelloOAuth(BaseOAuth1): 9 | 10 | """Trello OAuth authentication backend""" 11 | name = 'trello' 12 | ID_KEY = 'username' 13 | AUTHORIZATION_URL = 'https://trello.com/1/OAuthAuthorizeToken' 14 | REQUEST_TOKEN_URL = 'https://trello.com/1/OAuthGetRequestToken' 15 | ACCESS_TOKEN_URL = 'https://trello.com/1/OAuthGetAccessToken' 16 | 17 | EXTRA_DATA = [ 18 | ('username', 'username'), 19 | ('email', 'email'), 20 | ('fullName', 'fullName') 21 | ] 22 | 23 | def get_user_details(self, response): 24 | """Return user details from Trello account""" 25 | fullname, first_name, last_name = self.get_user_names( 26 | response.get('fullName') 27 | ) 28 | return {'username': response.get('username'), 29 | 'email': response.get('email'), 30 | 'fullname': fullname, 31 | 'first_name': first_name, 32 | 'last_name': last_name} 33 | 34 | def user_data(self, access_token): 35 | """Return user data provided""" 36 | url = 'https://trello.com/1/members/me' 37 | try: 38 | return self.get_json(url, auth=self.oauth_auth(access_token)) 39 | except ValueError: 40 | return None 41 | 42 | def auth_extra_arguments(self): 43 | return { 44 | 'name': self.setting('APP_NAME', ''), 45 | # trello default expiration is '30days' 46 | 'expiration': self.setting('EXPIRATION', 'never') 47 | } 48 | -------------------------------------------------------------------------------- /social_core/backends/tumblr.py: -------------------------------------------------------------------------------- 1 | """ 2 | Tumblr OAuth1 backend, docs at: 3 | https://python-social-auth.readthedocs.io/en/latest/backends/tumblr.html 4 | """ 5 | from ..utils import first 6 | from .oauth import BaseOAuth1 7 | 8 | 9 | class TumblrOAuth(BaseOAuth1): 10 | name = 'tumblr' 11 | ID_KEY = 'name' 12 | AUTHORIZATION_URL = 'http://www.tumblr.com/oauth/authorize' 13 | REQUEST_TOKEN_URL = 'http://www.tumblr.com/oauth/request_token' 14 | REQUEST_TOKEN_METHOD = 'POST' 15 | ACCESS_TOKEN_URL = 'http://www.tumblr.com/oauth/access_token' 16 | 17 | def get_user_id(self, details, response): 18 | return response['response']['user'][self.ID_KEY] 19 | 20 | def get_user_details(self, response): 21 | # http://www.tumblr.com/docs/en/api/v2#user-methods 22 | user_info = response['response']['user'] 23 | data = {'username': user_info['name']} 24 | blog = first(lambda blog: blog['primary'], user_info['blogs']) 25 | if blog: 26 | data['fullname'] = blog['title'] 27 | return data 28 | 29 | def user_data(self, access_token): 30 | return self.get_json('http://api.tumblr.com/v2/user/info', 31 | auth=self.oauth_auth(access_token)) 32 | -------------------------------------------------------------------------------- /social_core/backends/twilio.py: -------------------------------------------------------------------------------- 1 | """ 2 | Twilio auth backend, docs at: 3 | https://python-social-auth.readthedocs.io/en/latest/backends/twilio.html 4 | """ 5 | from re import sub 6 | 7 | from six.moves.urllib_parse import urlencode 8 | 9 | from .base import BaseAuth 10 | 11 | 12 | class TwilioAuth(BaseAuth): 13 | name = 'twilio' 14 | ID_KEY = 'AccountSid' 15 | 16 | def get_user_details(self, response): 17 | """Return twilio details, Twilio only provides AccountSID as 18 | parameters.""" 19 | # /complete/twilio/?AccountSid=ACc65ea16c9ebd4d4684edf814995b27e 20 | return {'username': response['AccountSid'], 21 | 'email': '', 22 | 'fullname': '', 23 | 'first_name': '', 24 | 'last_name': ''} 25 | 26 | def auth_url(self): 27 | """Return authorization redirect url.""" 28 | key, secret = self.get_key_and_secret() 29 | callback = self.strategy.absolute_uri(self.redirect_uri) 30 | callback = sub(r'^https', 'http', callback) 31 | query = urlencode({'cb': callback}) 32 | return 'https://www.twilio.com/authorize/{0}?{1}'.format(key, query) 33 | 34 | def auth_complete(self, *args, **kwargs): 35 | """Completes login process, must return user instance""" 36 | account_sid = self.data.get('AccountSid') 37 | if not account_sid: 38 | raise ValueError('No AccountSid returned') 39 | kwargs.update({'response': self.data, 'backend': self}) 40 | return self.strategy.authenticate(*args, **kwargs) 41 | -------------------------------------------------------------------------------- /social_core/backends/twitch.py: -------------------------------------------------------------------------------- 1 | """ 2 | Twitch OAuth2 backend, docs at: 3 | https://python-social-auth.readthedocs.io/en/latest/backends/twitch.html 4 | """ 5 | from .oauth import BaseOAuth2 6 | 7 | 8 | class TwitchOAuth2(BaseOAuth2): 9 | """Twitch OAuth authentication backend""" 10 | name = 'twitch' 11 | ID_KEY = '_id' 12 | AUTHORIZATION_URL = 'https://api.twitch.tv/kraken/oauth2/authorize' 13 | ACCESS_TOKEN_URL = 'https://api.twitch.tv/kraken/oauth2/token' 14 | ACCESS_TOKEN_METHOD = 'POST' 15 | DEFAULT_SCOPE = ['user_read'] 16 | REDIRECT_STATE = False 17 | 18 | def get_user_details(self, response): 19 | return { 20 | 'username': response.get('name'), 21 | 'email': response.get('email'), 22 | 'first_name': '', 23 | 'last_name': '' 24 | } 25 | 26 | def user_data(self, access_token, *args, **kwargs): 27 | return self.get_json( 28 | 'https://api.twitch.tv/kraken/user/', 29 | params={'oauth_token': access_token} 30 | ) 31 | -------------------------------------------------------------------------------- /social_core/backends/twitter.py: -------------------------------------------------------------------------------- 1 | """ 2 | Twitter OAuth1 backend, docs at: 3 | https://python-social-auth.readthedocs.io/en/latest/backends/twitter.html 4 | """ 5 | from .oauth import BaseOAuth1 6 | from ..exceptions import AuthCanceled 7 | 8 | 9 | class TwitterOAuth(BaseOAuth1): 10 | """Twitter OAuth authentication backend""" 11 | name = 'twitter' 12 | EXTRA_DATA = [('id', 'id')] 13 | REQUEST_TOKEN_METHOD = 'POST' 14 | ACCESS_TOKEN_METHOD = 'POST' 15 | AUTHORIZATION_URL = 'https://api.twitter.com/oauth/authenticate' 16 | REQUEST_TOKEN_URL = 'https://api.twitter.com/oauth/request_token' 17 | ACCESS_TOKEN_URL = 'https://api.twitter.com/oauth/access_token' 18 | REDIRECT_STATE = True 19 | 20 | def process_error(self, data): 21 | if 'denied' in data: 22 | raise AuthCanceled(self) 23 | else: 24 | super(TwitterOAuth, self).process_error(data) 25 | 26 | def get_user_details(self, response): 27 | """Return user details from Twitter account""" 28 | fullname, first_name, last_name = self.get_user_names(response['name']) 29 | return {'username': response['screen_name'], 30 | 'email': response.get('email', ''), 31 | 'fullname': fullname, 32 | 'first_name': first_name, 33 | 'last_name': last_name} 34 | 35 | def user_data(self, access_token, *args, **kwargs): 36 | """Return user data provided""" 37 | return self.get_json( 38 | 'https://api.twitter.com/1.1/account/verify_credentials.json', 39 | params={'include_email': 'true'}, 40 | auth=self.oauth_auth(access_token) 41 | ) 42 | -------------------------------------------------------------------------------- /social_core/backends/uber.py: -------------------------------------------------------------------------------- 1 | """ 2 | Uber OAuth2 backend, docs at: 3 | https://python-social-auth.readthedocs.io/en/latest/backends/uber.html 4 | """ 5 | from .oauth import BaseOAuth2 6 | 7 | 8 | class UberOAuth2(BaseOAuth2): 9 | name = 'uber' 10 | ID_KEY = 'uuid' 11 | SCOPE_SEPARATOR = ' ' 12 | AUTHORIZATION_URL = 'https://login.uber.com/oauth/authorize' 13 | ACCESS_TOKEN_URL = 'https://login.uber.com/oauth/token' 14 | ACCESS_TOKEN_METHOD = 'POST' 15 | 16 | def auth_complete_credentials(self): 17 | return self.get_key_and_secret() 18 | 19 | def get_user_details(self, response): 20 | """Return user details from Uber account""" 21 | email = response.get('email', '') 22 | fullname, first_name, last_name = self.get_user_names( 23 | '', 24 | response.get('first_name', ''), 25 | response.get('last_name', '') 26 | ) 27 | return {'username': email, 28 | 'email': email, 29 | 'fullname': fullname, 30 | 'first_name': first_name, 31 | 'last_name': last_name} 32 | 33 | def user_data(self, access_token, *args, **kwargs): 34 | """Loads user data from service""" 35 | response = kwargs.pop('response') 36 | return self.get_json('https://api.uber.com/v1/me', headers={ 37 | 'Authorization': '{0} {1}'.format(response.get('token_type'), 38 | access_token) 39 | }) 40 | -------------------------------------------------------------------------------- /social_core/backends/ubuntu.py: -------------------------------------------------------------------------------- 1 | """ 2 | Ubuntu One OpenId backend 3 | """ 4 | from .open_id import OpenIdAuth 5 | 6 | 7 | class UbuntuOpenId(OpenIdAuth): 8 | name = 'ubuntu' 9 | URL = 'https://login.ubuntu.com' 10 | 11 | def get_user_id(self, details, response): 12 | """ 13 | Return user unique id provided by service. For Ubuntu One 14 | the nickname should be original. 15 | """ 16 | return details['nickname'] 17 | -------------------------------------------------------------------------------- /social_core/backends/udata.py: -------------------------------------------------------------------------------- 1 | """ 2 | Udata related backends. 3 | 4 | Docs at: 5 | https://python-social-auth.readthedocs.io/en/latest/backends/udata.html 6 | """ 7 | from .oauth import BaseOAuth2 8 | 9 | 10 | class UdataBaseOAuth2(BaseOAuth2): 11 | """Udata base OAuth authentication backend.""" 12 | SCOPE_SEPARATOR = ',' 13 | REDIRECT_STATE = False 14 | DEFAULT_SCOPE = ['default'] 15 | ACCESS_TOKEN_METHOD = 'POST' 16 | 17 | def get_user_details(self, response): 18 | """Return user details from Udata account.""" 19 | return { 20 | 'username': response.get('first_name'), 21 | 'email': response.get('email') or '', 22 | 'first_name': response.get('first_name') 23 | } 24 | 25 | def user_data(self, access_token, *args, **kwargs): 26 | """Load user data from service.""" 27 | return self.get_json(self.USER_DATA_URL, params={ 28 | 'access_token': access_token 29 | }) 30 | 31 | 32 | class DatagouvfrOAuth2(UdataBaseOAuth2): 33 | """Datagouvfr OAuth authentication backend.""" 34 | name = 'datagouv' 35 | ACCESS_TOKEN_URL = 'https://www.data.gouv.fr/oauth/token' 36 | AUTHORIZATION_URL = 'https://www.data.gouv.fr/oauth/authorize' 37 | USER_DATA_URL = 'https://www.data.gouv.fr/api/1/me/' 38 | -------------------------------------------------------------------------------- /social_core/backends/upwork.py: -------------------------------------------------------------------------------- 1 | """ 2 | Upwork OAuth1 backend 3 | """ 4 | from .oauth import BaseOAuth1 5 | 6 | 7 | class UpworkOAuth(BaseOAuth1): 8 | """Upwork OAuth authentication backend""" 9 | name = 'upwork' 10 | ID_KEY = 'id' 11 | AUTHORIZATION_URL = 'https://www.upwork.com/services/api/auth' 12 | REQUEST_TOKEN_URL = \ 13 | 'https://www.upwork.com/api/auth/v1/oauth/token/request' 14 | REQUEST_TOKEN_METHOD = 'POST' 15 | ACCESS_TOKEN_URL = 'https://www.upwork.com/api/auth/v1/oauth/token/access' 16 | ACCESS_TOKEN_METHOD = 'POST' 17 | REDIRECT_URI_PARAMETER_NAME = 'oauth_callback' 18 | 19 | def get_user_details(self, response): 20 | """Return user details from Upwork account""" 21 | info = response.get('info', {}) 22 | auth_user = response.get('auth_user', {}) 23 | first_name = auth_user.get('first_name') 24 | last_name = auth_user.get('last_name') 25 | fullname = '{} {}'.format(first_name, last_name) 26 | profile_url = info.get('profile_url', '') 27 | username = profile_url.rsplit('/')[-1].replace('~', '') 28 | return { 29 | 'username': username, 30 | 'fullname': fullname, 31 | 'first_name': first_name, 32 | 'last_name': last_name 33 | } 34 | 35 | def user_data(self, access_token, *args, **kwargs): 36 | """Loads user data from service""" 37 | return self.get_json( 38 | 'https://www.upwork.com/api/auth/v1/info.json', 39 | auth=self.oauth_auth(access_token) 40 | ) 41 | -------------------------------------------------------------------------------- /social_core/backends/username.py: -------------------------------------------------------------------------------- 1 | """ 2 | Legacy Username backend, docs at: 3 | https://python-social-auth.readthedocs.io/en/latest/backends/username.html 4 | """ 5 | from .legacy import LegacyAuth 6 | 7 | 8 | class UsernameAuth(LegacyAuth): 9 | name = 'username' 10 | ID_KEY = 'username' 11 | EXTRA_DATA = ['username'] 12 | -------------------------------------------------------------------------------- /social_core/backends/vend.py: -------------------------------------------------------------------------------- 1 | """ 2 | Vend OAuth2 backend: 3 | """ 4 | from .oauth import BaseOAuth2 5 | 6 | 7 | class VendOAuth2(BaseOAuth2): 8 | name = 'vend' 9 | AUTHORIZATION_URL = 'https://secure.vendhq.com/connect' 10 | ACCESS_TOKEN_URL = 'https://{0}.vendhq.com/api/1.0/token' 11 | ACCESS_TOKEN_METHOD = 'POST' 12 | REDIRECT_STATE = False 13 | EXTRA_DATA = [ 14 | ('refresh_token', 'refresh_token'), 15 | ('domain_prefix', 'domain_prefix') 16 | ] 17 | 18 | def access_token_url(self): 19 | return self.ACCESS_TOKEN_URL.format(self.data['domain_prefix']) 20 | 21 | def get_user_details(self, response): 22 | email = response['email'] 23 | username = response.get('username') or email.split('@', 1)[0] 24 | return { 25 | 'username': username, 26 | 'email': email, 27 | 'fullname': '', 28 | 'first_name': '', 29 | 'last_name': '' 30 | } 31 | 32 | def user_data(self, access_token, *args, **kwargs): 33 | """Loads user data from service""" 34 | prefix = kwargs['response']['domain_prefix'] 35 | url = 'https://{0}.vendhq.com/api/users'.format(prefix) 36 | data = self.get_json(url, headers={ 37 | 'Authorization': 'Bearer {0}'.format(access_token) 38 | }) 39 | return data['users'][0] if data.get('users') else {} 40 | -------------------------------------------------------------------------------- /social_core/backends/withings.py: -------------------------------------------------------------------------------- 1 | from .oauth import BaseOAuth1 2 | 3 | 4 | class WithingsOAuth(BaseOAuth1): 5 | name = 'withings' 6 | AUTHORIZATION_URL = 'https://developer.health.nokia.com/account/authorize' 7 | REQUEST_TOKEN_URL = 'https://developer.health.nokia.com/account/request_token' 8 | ACCESS_TOKEN_URL = 'https://developer.health.nokia.com/account/access_token' 9 | ID_KEY = 'userid' 10 | 11 | def get_user_details(self, response): 12 | """Return user details from Withings account""" 13 | return {'userid': response['access_token']['userid'], 14 | 'email': ''} 15 | -------------------------------------------------------------------------------- /social_core/backends/wunderlist.py: -------------------------------------------------------------------------------- 1 | from .oauth import BaseOAuth2 2 | 3 | 4 | class WunderlistOAuth2(BaseOAuth2): 5 | """Wunderlist OAuth2 authentication backend""" 6 | name = 'wunderlist' 7 | AUTHORIZATION_URL = 'https://www.wunderlist.com/oauth/authorize' 8 | ACCESS_TOKEN_URL = 'https://www.wunderlist.com/oauth/access_token' 9 | ACCESS_TOKEN_METHOD = 'POST' 10 | REDIRECT_STATE = False 11 | 12 | def get_user_details(self, response): 13 | """Return user details from Wunderlist account""" 14 | fullname, first_name, last_name = self.get_user_names( 15 | response.get('name') 16 | ) 17 | return {'username': str(response.get('id')), 18 | 'email': response.get('email'), 19 | 'fullname': fullname, 20 | 'first_name': first_name, 21 | 'last_name': last_name} 22 | 23 | def user_data(self, access_token, *args, **kwargs): 24 | """Loads user data from service""" 25 | headers = { 26 | 'X-Access-Token': access_token, 27 | 'X-Client-ID': self.setting('KEY')} 28 | return self.get_json( 29 | 'https://a.wunderlist.com/api/v1/user', headers=headers) 30 | -------------------------------------------------------------------------------- /social_core/backends/yammer.py: -------------------------------------------------------------------------------- 1 | """ 2 | Yammer OAuth2 production and staging backends, docs at: 3 | https://python-social-auth.readthedocs.io/en/latest/backends/yammer.html 4 | """ 5 | from .oauth import BaseOAuth2 6 | 7 | 8 | class YammerOAuth2(BaseOAuth2): 9 | name = 'yammer' 10 | AUTHORIZATION_URL = 'https://www.yammer.com/dialog/oauth' 11 | ACCESS_TOKEN_URL = 'https://www.yammer.com/oauth2/access_token' 12 | EXTRA_DATA = [ 13 | ('id', 'id'), 14 | ('expires', 'expires'), 15 | ('mugshot_url', 'mugshot_url') 16 | ] 17 | 18 | def get_user_id(self, details, response): 19 | return response['user']['id'] 20 | 21 | def get_user_details(self, response): 22 | username = response['user']['name'] 23 | fullname, first_name, last_name = self.get_user_names( 24 | fullname=response['user']['full_name'], 25 | first_name=response['user']['first_name'], 26 | last_name=response['user']['last_name'] 27 | ) 28 | email = response['user']['contact']['email_addresses'][0]['address'] 29 | mugshot_url = response['user']['mugshot_url'] 30 | return { 31 | 'username': username, 32 | 'email': email, 33 | 'fullname': fullname, 34 | 'first_name': first_name, 35 | 'last_name': last_name, 36 | 'picture_url': mugshot_url 37 | } 38 | 39 | 40 | class YammerStagingOAuth2(YammerOAuth2): 41 | name = 'yammer-staging' 42 | AUTHORIZATION_URL = 'https://www.staging.yammer.com/dialog/oauth' 43 | ACCESS_TOKEN_URL = 'https://www.staging.yammer.com/oauth2/access_token' 44 | REQUEST_TOKEN_URL = 'https://www.staging.yammer.com/oauth2/request_token' 45 | -------------------------------------------------------------------------------- /social_core/backends/zotero.py: -------------------------------------------------------------------------------- 1 | """ 2 | Zotero OAuth1 backends, docs at: 3 | https://python-social-auth.readthedocs.io/en/latest/backends/zotero.html 4 | """ 5 | from .oauth import BaseOAuth1 6 | 7 | 8 | class ZoteroOAuth(BaseOAuth1): 9 | 10 | """Zotero OAuth authorization mechanism""" 11 | name = 'zotero' 12 | AUTHORIZATION_URL = 'https://www.zotero.org/oauth/authorize' 13 | REQUEST_TOKEN_URL = 'https://www.zotero.org/oauth/request' 14 | ACCESS_TOKEN_URL = 'https://www.zotero.org/oauth/access' 15 | 16 | def get_user_id(self, details, response): 17 | """ 18 | Return user unique id provided by service. For Ubuntu One 19 | the nickname should be original. 20 | """ 21 | return details['userID'] 22 | 23 | def get_user_details(self, response): 24 | """Return user details from Zotero API account""" 25 | access_token = response.get('access_token', {}) 26 | return { 27 | 'username': access_token.get('username', ''), 28 | 'userID': access_token.get('userID', '') 29 | } 30 | -------------------------------------------------------------------------------- /social_core/pipeline/debug.py: -------------------------------------------------------------------------------- 1 | from pprint import pprint 2 | 3 | 4 | def debug(response, details, *args, **kwargs): 5 | print('=' * 80) 6 | pprint(response) 7 | print('=' * 80) 8 | pprint(details) 9 | print('=' * 80) 10 | pprint(args) 11 | print('=' * 80) 12 | pprint(kwargs) 13 | print('=' * 80) 14 | -------------------------------------------------------------------------------- /social_core/pipeline/disconnect.py: -------------------------------------------------------------------------------- 1 | from ..exceptions import NotAllowedToDisconnect 2 | 3 | 4 | def allowed_to_disconnect(strategy, user, name, user_storage, 5 | association_id=None, *args, **kwargs): 6 | if not user_storage.allowed_to_disconnect(user, name, association_id): 7 | raise NotAllowedToDisconnect() 8 | 9 | 10 | def get_entries(strategy, user, name, user_storage, association_id=None, 11 | *args, **kwargs): 12 | return { 13 | 'entries': user_storage.get_social_auth_for_user( 14 | user, name, association_id 15 | ) 16 | } 17 | 18 | 19 | def revoke_tokens(strategy, entries, *args, **kwargs): 20 | revoke_tokens = strategy.setting('REVOKE_TOKENS_ON_DISCONNECT', False) 21 | if revoke_tokens: 22 | for entry in entries: 23 | if 'access_token' in entry.extra_data: 24 | backend = entry.get_backend(strategy)(strategy) 25 | backend.revoke_token(entry.extra_data['access_token'], 26 | entry.uid) 27 | 28 | 29 | def disconnect(strategy, entries, user_storage, *args, **kwargs): 30 | for entry in entries: 31 | user_storage.disconnect(entry) 32 | -------------------------------------------------------------------------------- /social_core/pipeline/mail.py: -------------------------------------------------------------------------------- 1 | from ..exceptions import InvalidEmail 2 | from .partial import partial 3 | 4 | 5 | @partial 6 | def mail_validation(backend, details, is_new=False, *args, **kwargs): 7 | requires_validation = backend.REQUIRES_EMAIL_VALIDATION or \ 8 | backend.setting('FORCE_EMAIL_VALIDATION', False) 9 | send_validation = details.get('email') and \ 10 | (is_new or backend.setting('PASSWORDLESS', False)) 11 | if requires_validation and send_validation: 12 | data = backend.strategy.request_data() 13 | if 'verification_code' in data: 14 | backend.strategy.session_pop('email_validation_address') 15 | if not backend.strategy.validate_email(details['email'], 16 | data['verification_code']): 17 | raise InvalidEmail(backend) 18 | else: 19 | current_partial = kwargs.get('current_partial') 20 | backend.strategy.send_email_validation(backend, 21 | details['email'], 22 | current_partial.token) 23 | backend.strategy.session_set('email_validation_address', 24 | details['email']) 25 | return backend.strategy.redirect( 26 | backend.strategy.setting('EMAIL_VALIDATION_URL') 27 | ) 28 | -------------------------------------------------------------------------------- /social_core/tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/harvardfly/network_anomaly_detection/88f37dc53defb6a424f7f3124ccabc31eb9c274e/social_core/tests/__init__.py -------------------------------------------------------------------------------- /social_core/tests/actions/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/harvardfly/network_anomaly_detection/88f37dc53defb6a424f7f3124ccabc31eb9c274e/social_core/tests/actions/__init__.py -------------------------------------------------------------------------------- /social_core/tests/backends/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/harvardfly/network_anomaly_detection/88f37dc53defb6a424f7f3124ccabc31eb9c274e/social_core/tests/backends/__init__.py -------------------------------------------------------------------------------- /social_core/tests/backends/legacy.py: -------------------------------------------------------------------------------- 1 | import requests 2 | 3 | from httpretty import HTTPretty 4 | 5 | from ...utils import parse_qs 6 | from .base import BaseBackendTest 7 | 8 | 9 | class BaseLegacyTest(BaseBackendTest): 10 | form = '' 11 | response_body = '' 12 | 13 | def setUp(self): 14 | super(BaseLegacyTest, self).setUp() 15 | self.strategy.set_settings({ 16 | 'SOCIAL_AUTH_{0}_FORM_URL'.format(self.name): 17 | self.strategy.build_absolute_uri('/login/{0}'.format( 18 | self.backend.name)) 19 | }) 20 | 21 | def extra_settings(self): 22 | return {'SOCIAL_AUTH_{0}_FORM_URL'.format(self.name): 23 | '/login/{0}'.format(self.backend.name)} 24 | 25 | def do_start(self): 26 | start_url = self.strategy.build_absolute_uri(self.backend.start().url) 27 | HTTPretty.register_uri( 28 | HTTPretty.GET, 29 | start_url, 30 | status=200, 31 | body=self.form.format(self.complete_url) 32 | ) 33 | HTTPretty.register_uri( 34 | HTTPretty.POST, 35 | self.complete_url, 36 | status=200, 37 | body=self.response_body, 38 | content_type='application/x-www-form-urlencoded' 39 | ) 40 | response = requests.get(start_url) 41 | self.assertEqual(response.text, self.form.format(self.complete_url)) 42 | response = requests.post( 43 | self.complete_url, 44 | data=parse_qs(self.response_body) 45 | ) 46 | self.strategy.set_request_data(parse_qs(response.text), self.backend) 47 | return self.backend.complete() 48 | -------------------------------------------------------------------------------- /social_core/tests/backends/test_amazon.py: -------------------------------------------------------------------------------- 1 | import json 2 | 3 | from .oauth import OAuth2Test 4 | 5 | 6 | class AmazonOAuth2Test(OAuth2Test): 7 | backend_path = 'social_core.backends.amazon.AmazonOAuth2' 8 | user_data_url = 'https://www.amazon.com/ap/user/profile' 9 | expected_username = 'FooBar' 10 | access_token_body = json.dumps({ 11 | 'access_token': 'foobar', 12 | 'token_type': 'bearer' 13 | }) 14 | user_data_body = json.dumps({ 15 | 'user_id': 'amzn1.account.ABCDE1234', 16 | 'email': 'foo@bar.com', 17 | 'name': 'Foo Bar' 18 | }) 19 | 20 | def test_login(self): 21 | self.do_login() 22 | 23 | def test_partial_pipeline(self): 24 | self.do_partial_pipeline() 25 | 26 | 27 | class AmazonOAuth2BrokenServerResponseTest(OAuth2Test): 28 | backend_path = 'social_core.backends.amazon.AmazonOAuth2' 29 | user_data_url = 'https://www.amazon.com/ap/user/profile' 30 | expected_username = 'FooBar' 31 | access_token_body = json.dumps({ 32 | 'access_token': 'foobar', 33 | 'token_type': 'bearer' 34 | }) 35 | user_data_body = json.dumps({ 36 | 'Request-Id': '02GGTU7CWMNFTV3KH3J6', 37 | 'Profile': { 38 | 'Name': 'Foo Bar', 39 | 'CustomerId': 'amzn1.account.ABCDE1234', 40 | 'PrimaryEmail': 'foo@bar.com' 41 | } 42 | }) 43 | 44 | def test_login(self): 45 | self.do_login() 46 | 47 | def test_partial_pipeline(self): 48 | self.do_partial_pipeline() 49 | -------------------------------------------------------------------------------- /social_core/tests/backends/test_angel.py: -------------------------------------------------------------------------------- 1 | import json 2 | 3 | from .oauth import OAuth2Test 4 | 5 | 6 | class AngelOAuth2Test(OAuth2Test): 7 | backend_path = 'social_core.backends.angel.AngelOAuth2' 8 | user_data_url = 'https://api.angel.co/1/me/' 9 | access_token_body = json.dumps({ 10 | 'access_token': 'foobar', 11 | 'token_type': 'bearer' 12 | }) 13 | user_data_body = json.dumps({ 14 | 'facebook_url': 'http://www.facebook.com/foobar', 15 | 'bio': None, 16 | 'name': 'Foo Bar', 17 | 'roles': [], 18 | 'github_url': None, 19 | 'angellist_url': 'https://angel.co/foobar', 20 | 'image': 'https://graph.facebook.com/foobar/picture?type=square', 21 | 'linkedin_url': None, 22 | 'locations': [], 23 | 'twitter_url': None, 24 | 'what_ive_built': None, 25 | 'dribbble_url': None, 26 | 'behance_url': None, 27 | 'blog_url': None, 28 | 'aboutme_url': None, 29 | 'follower_count': 0, 30 | 'online_bio_url': None, 31 | 'id': 101010 32 | }) 33 | expected_username = 'foobar' 34 | 35 | def test_login(self): 36 | self.do_login() 37 | 38 | def test_partial_pipeline(self): 39 | self.do_partial_pipeline() 40 | -------------------------------------------------------------------------------- /social_core/tests/backends/test_arcgis.py: -------------------------------------------------------------------------------- 1 | import json 2 | from .oauth import OAuth2Test 3 | 4 | 5 | class ArcGISOAuth2Test(OAuth2Test): 6 | user_data_url = 'https://www.arcgis.com/sharing/rest/community/self' 7 | backend_path = 'social_core.backends.arcgis.ArcGISOAuth2' 8 | expected_username = 'gis@rocks.com' 9 | 10 | user_data_body = json.dumps({ 11 | 'first_name': 'Gis', 12 | 'last_name': 'Rocks', 13 | 'email': 'gis@rocks.com', 14 | 'fullName': 'Gis Rocks', 15 | 'username': 'gis@rocks.com' 16 | }) 17 | 18 | access_token_body = json.dumps({ 19 | 'access_token': 'CM-gcB85taGhRmoI7l3PSGaXUNsaLkTg-dHH7XtA9Dnlin' \ 20 | 'PYKBBrIvFzhd1JtDhh7hEwSv_6eLLcLtUqe3gD6i1yaYYF' \ 21 | 'pUQJwy8KEujke5AE87tP9XIoMtp4_l320pUL', 22 | 'expires_in': 86400 23 | }) 24 | 25 | def test_login(self): 26 | self.do_login() 27 | 28 | def test_partial_pipeline(self): 29 | self.do_partial_pipeline() 30 | -------------------------------------------------------------------------------- /social_core/tests/backends/test_asana.py: -------------------------------------------------------------------------------- 1 | import json 2 | 3 | from .oauth import OAuth2Test 4 | 5 | 6 | class AsanaOAuth2Test(OAuth2Test): 7 | backend_path = 'social_core.backends.asana.AsanaOAuth2' 8 | user_data_url = 'https://app.asana.com/api/1.0/users/me' 9 | expected_username = 'erlich@bachmanity.com' 10 | access_token_body = json.dumps({ 11 | 'access_token': 'aviato', 12 | 'token_type': 'bearer' 13 | }) 14 | # https://asana.com/developers/api-reference/users 15 | user_data_body = json.dumps({ 16 | 'data': { 17 | 'id': 12345, 18 | 'name': 'Erlich Bachman', 19 | 'email': 'erlich@bachmanity.com', 20 | 'photo': None, 21 | 'workspaces': [ 22 | { 23 | 'id': 123456, 24 | 'name': 'Pied Piper' 25 | } 26 | ] 27 | } 28 | }) 29 | 30 | def test_login(self): 31 | self.do_login() 32 | 33 | def test_partial_pipeline(self): 34 | self.do_partial_pipeline() 35 | -------------------------------------------------------------------------------- /social_core/tests/backends/test_broken.py: -------------------------------------------------------------------------------- 1 | import unittest2 as unittest 2 | 3 | from ...backends.base import BaseAuth 4 | from ..strategy import TestStrategy 5 | from ..models import TestStorage 6 | 7 | 8 | class BrokenBackendAuth(BaseAuth): 9 | name = 'broken' 10 | 11 | 12 | class BrokenBackendTest(unittest.TestCase): 13 | def setUp(self): 14 | self.backend = BrokenBackendAuth(TestStrategy(TestStorage)) 15 | 16 | def tearDown(self): 17 | self.backend = None 18 | 19 | def test_auth_url(self): 20 | with self.assertRaisesRegexp(NotImplementedError, 21 | 'Implement in subclass'): 22 | self.backend.auth_url() 23 | 24 | def test_auth_html(self): 25 | with self.assertRaisesRegexp(NotImplementedError, 26 | 'Implement in subclass'): 27 | self.backend.auth_html() 28 | 29 | def test_auth_complete(self): 30 | with self.assertRaisesRegexp(NotImplementedError, 31 | 'Implement in subclass'): 32 | self.backend.auth_complete() 33 | 34 | def test_get_user_details(self): 35 | with self.assertRaisesRegexp(NotImplementedError, 36 | 'Implement in subclass'): 37 | self.backend.get_user_details(None) 38 | -------------------------------------------------------------------------------- /social_core/tests/backends/test_chatwork.py: -------------------------------------------------------------------------------- 1 | import json 2 | 3 | from .oauth import OAuth2Test 4 | 5 | 6 | class ChatworkOAuth2Test(OAuth2Test): 7 | backend_path = 'social_core.backends.chatwork.ChatworkOAuth2' 8 | user_data_url = 'https://api.chatwork.com/v2/me' 9 | expected_username = 'hogehoge' 10 | access_token_body = json.dumps({ 11 | 'access_token': 'pyopyopyopyopyopyopyopyopyopyo', 12 | 'token_type': 'Bearer', 13 | 'expires_in': '1501138041000', 14 | 'refresh_token': 'pyopyopyopyopyopyo', 15 | 'scope': 'rooms.all:read_write' 16 | }) 17 | 18 | user_data_body = json.dumps({ 19 | 'account_id': 123, 20 | 'room_id': 322, 21 | 'name': 'Foo Bar', 22 | 'chatwork_id': 'hogehoge', 23 | 'organization_id': 101, 24 | 'organization_name': 'Foo foobar', 25 | 'department': 'Support', 26 | 'title': 'CMO', 27 | 'url': 'http://www.example.com', 28 | 'introduction': '', 29 | 'mail': 'hogehoge@example.com', 30 | 'tel_organization': '', 31 | 'tel_extension': '', 32 | 'tel_mobile': '', 33 | 'skype': '', 34 | 'facebook': '', 35 | 'twitter': '', 36 | 'avatar_image_url': 'https://www.example.com/hogehoge.jpg', 37 | 'login_mail': 'hogehoge@example.com' 38 | }) 39 | 40 | def test_login(self): 41 | self.do_login() 42 | 43 | def test_partial_pipeline(self): 44 | self.do_partial_pipeline() 45 | -------------------------------------------------------------------------------- /social_core/tests/backends/test_clef.py: -------------------------------------------------------------------------------- 1 | import json 2 | 3 | from .oauth import OAuth2Test 4 | 5 | 6 | class ClefOAuth2Test(OAuth2Test): 7 | backend_path = 'social_core.backends.clef.ClefOAuth2' 8 | user_data_url = 'https://clef.io/api/v1/info' 9 | expected_username = 'test' 10 | access_token_body = json.dumps({ 11 | 'access_token': 'foobar' 12 | }) 13 | user_data_body = json.dumps({ 14 | 'info': { 15 | 'id': '123456789', 16 | 'first_name': 'Test', 17 | 'last_name': 'User', 18 | 'email': 'test@example.com' 19 | } 20 | }) 21 | 22 | def test_login(self): 23 | self.do_login() 24 | 25 | def test_partial_pipeline(self): 26 | self.do_partial_pipeline() 27 | -------------------------------------------------------------------------------- /social_core/tests/backends/test_coinbase.py: -------------------------------------------------------------------------------- 1 | import json 2 | 3 | from .oauth import OAuth2Test 4 | 5 | 6 | class CoinbaseOAuth2Test(OAuth2Test): 7 | backend_path = 'social_core.backends.coinbase.CoinbaseOAuth2' 8 | user_data_url = 'https://api.coinbase.com/v2/user' 9 | expected_username = 'satoshi_nakomoto' 10 | access_token_body = json.dumps({ 11 | 'access_token': 'foobar', 12 | 'token_type': 'bearer' 13 | }) 14 | user_data_body = json.dumps({ 15 | "data": { 16 | "id": "1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa", 17 | 'name': "Satoshi Nakamoto", 18 | "username": "satoshi_nakomoto", 19 | "profile_location": None, 20 | "profile_bio": None, 21 | "profile_url": "https://coinbase.com/satoshi_nakomoto", 22 | "avatar_url": None, 23 | "resource": "user", 24 | "resource_path": "/v2/user" 25 | } 26 | }) 27 | 28 | def test_login(self): 29 | self.do_login() 30 | 31 | def test_partial_pipeline(self): 32 | self.do_partial_pipeline() 33 | -------------------------------------------------------------------------------- /social_core/tests/backends/test_coursera.py: -------------------------------------------------------------------------------- 1 | import json 2 | 3 | from .oauth import OAuth2Test 4 | 5 | 6 | class CourseraOAuth2Test(OAuth2Test): 7 | backend_path = 'social_core.backends.coursera.CourseraOAuth2' 8 | user_data_url = \ 9 | 'https://api.coursera.org/api/externalBasicProfiles.v1?q=me' 10 | expected_username = '560e7ed2076e0d589e88bd74b6aad4b7' 11 | access_token_body = json.dumps({ 12 | 'access_token': 'foobar', 13 | 'token_type': 'Bearer', 14 | 'expires_in': 1795 15 | }) 16 | request_token_body = json.dumps({ 17 | 'code': 'foobar-code', 18 | 'client_id': 'foobar-client-id', 19 | 'client_secret': 'foobar-client-secret', 20 | 'redirect_uri': 'http://localhost:8000/accounts/coursera/', 21 | 'grant_type': 'authorization_code' 22 | }) 23 | user_data_body = json.dumps({ 24 | 'token_type': 'Bearer', 25 | 'paging': None, 26 | 'elements': [{ 27 | 'id': '560e7ed2076e0d589e88bd74b6aad4b7' 28 | }], 29 | 'access_token': 'foobar', 30 | 'expires_in': 1800, 31 | 'linked': None 32 | }) 33 | 34 | def test_login(self): 35 | self.do_login() 36 | 37 | def test_partial_pipeline(self): 38 | self.do_partial_pipeline() 39 | -------------------------------------------------------------------------------- /social_core/tests/backends/test_dailymotion.py: -------------------------------------------------------------------------------- 1 | import json 2 | 3 | from .oauth import OAuth2Test 4 | 5 | 6 | class DailymotionOAuth2Test(OAuth2Test): 7 | backend_path = 'social_core.backends.dailymotion.DailymotionOAuth2' 8 | user_data_url = 'https://api.dailymotion.com/auth/' 9 | expected_username = 'foobar' 10 | access_token_body = json.dumps({ 11 | 'access_token': 'foobar', 12 | 'token_type': 'bearer' 13 | }) 14 | user_data_body = json.dumps({ 15 | 'id': 'foobar', 16 | 'screenname': 'foobar' 17 | }) 18 | 19 | def test_login(self): 20 | self.do_login() 21 | 22 | def test_partial_pipeline(self): 23 | self.do_partial_pipeline() 24 | -------------------------------------------------------------------------------- /social_core/tests/backends/test_deezer.py: -------------------------------------------------------------------------------- 1 | import json 2 | 3 | from .oauth import OAuth2Test 4 | 5 | 6 | class DeezerOAuth2Test(OAuth2Test): 7 | backend_path = 'social_core.backends.deezer.DeezerOAuth2' 8 | user_data_url = 'http://api.deezer.com/user/me' 9 | expected_username = 'foobar' 10 | access_token_body = 'access_token=foobar&expires=0' 11 | user_data_body = json.dumps({ 12 | 'id': '1', 13 | 'name': 'foobar', 14 | 'lastname': '', 15 | 'firstname': '', 16 | 'status': 0, 17 | 'birthday': '1970-01-01', 18 | 'inscription_date': '2015-01-01', 19 | 'gender': 'M', 20 | 'link': 'https://www.deezer.com/profile/1', 21 | 'picture': 'https://api.deezer.com/user/1/image', 22 | 'picture_small': 'https://cdns-images.dzcdn.net/images/user//56x56-000000-80-0-0.jpg', 23 | 'picture_medium': 'https://cdns-images.dzcdn.net/images/user//250x250-000000-80-0-0.jpg', 24 | 'picture_big': 'https://cdns-images.dzcdn.net/images/user//500x500-000000-80-0-0.jpg', 25 | 'country': 'FR', 26 | 'lang': 'FR', 27 | 'is_kid': False, 28 | 'tracklist': 'https://api.deezer.com/user/1/flow', 29 | 'type': 'user' 30 | }) 31 | 32 | def test_login(self): 33 | self.do_login() 34 | 35 | def test_partial_pipeline(self): 36 | self.do_partial_pipeline() 37 | -------------------------------------------------------------------------------- /social_core/tests/backends/test_digitalocean.py: -------------------------------------------------------------------------------- 1 | import json 2 | 3 | from .oauth import OAuth2Test 4 | 5 | 6 | class DigitalOceanOAuthTest(OAuth2Test): 7 | backend_path = 'social_core.backends.digitalocean.DigitalOceanOAuth' 8 | user_data_url = 'https://api.digitalocean.com/v2/account' 9 | expected_username = 'sammy@digitalocean.com' 10 | access_token_body = json.dumps({ 11 | 'access_token': '547cac21118ae7', 12 | 'token_type': 'bearer', 13 | 'expires_in': 2592000, 14 | 'refresh_token': '00a3aae641658d', 15 | 'scope': 'read write', 16 | 'info': { 17 | 'name': 'Sammy Shark', 18 | 'email': 'sammy@digitalocean.com' 19 | } 20 | }) 21 | user_data_body = json.dumps({ 22 | "account": { 23 | 'droplet_limit': 25, 24 | 'email': 'sammy@digitalocean.com', 25 | 'uuid': 'b6fr89dbf6d9156cace5f3c78dc9851d957381ef', 26 | 'email_verified': True 27 | } 28 | }) 29 | 30 | def test_login(self): 31 | self.do_login() 32 | 33 | def test_partial_pipeline(self): 34 | self.do_partial_pipeline() 35 | -------------------------------------------------------------------------------- /social_core/tests/backends/test_dribbble.py: -------------------------------------------------------------------------------- 1 | import json 2 | 3 | from .oauth import OAuth2Test 4 | 5 | 6 | class DribbbleOAuth2Test(OAuth2Test): 7 | backend_path = 'social_core.backends.dribbble.DribbbleOAuth2' 8 | user_data_url = 'https://api.dribbble.com/v1/user' 9 | expected_username = 'foobar' 10 | 11 | access_token_body = json.dumps({ 12 | 'access_token': 'foobar', 13 | 'token_type': 'bearer' 14 | }) 15 | 16 | user_data_body = json.dumps({ 17 | 'id': 'foobar', 18 | 'username': 'foobar', 19 | 'name': 'Foo Bar' 20 | }) 21 | 22 | def test_login(self): 23 | self.do_login() 24 | 25 | def test_partial_pipeline(self): 26 | self.do_partial_pipeline() 27 | -------------------------------------------------------------------------------- /social_core/tests/backends/test_drip.py: -------------------------------------------------------------------------------- 1 | import json 2 | 3 | from .oauth import OAuth2Test 4 | 5 | 6 | class DripOAuthTest(OAuth2Test): 7 | backend_path = 'social_core.backends.drip.DripOAuth' 8 | user_data_url = 'https://api.getdrip.com/v2/user' 9 | expected_username = 'other@example.com' 10 | access_token_body = json.dumps({ 11 | 'access_token': '822bbf7cd12243df', 12 | 'token_type': 'bearer', 13 | 'scope': 'public' 14 | }) 15 | 16 | user_data_body = json.dumps({ 17 | 'users': [ 18 | { 19 | 'email': 'other@example.com', 20 | 'name': None 21 | } 22 | ] 23 | }) 24 | 25 | def test_login(self): 26 | self.do_login() 27 | 28 | def test_partial_pipeline(self): 29 | self.do_partial_pipeline() 30 | -------------------------------------------------------------------------------- /social_core/tests/backends/test_dropbox.py: -------------------------------------------------------------------------------- 1 | import json 2 | 3 | from six.moves.urllib_parse import urlencode 4 | 5 | from .oauth import OAuth1Test 6 | 7 | 8 | class DropboxOAuth1Test(OAuth1Test): 9 | backend_path = 'social_core.backends.dropbox.DropboxOAuth' 10 | user_data_url = 'https://api.dropbox.com/1/account/info' 11 | expected_username = '10101010' 12 | access_token_body = json.dumps({ 13 | 'access_token': 'foobar', 14 | 'token_type': 'bearer' 15 | }) 16 | request_token_body = urlencode({ 17 | 'oauth_token_secret': 'foobar-secret', 18 | 'oauth_token': 'foobar', 19 | 'oauth_callback_confirmed': 'true' 20 | }) 21 | user_data_body = json.dumps({ 22 | 'referral_link': 'https://www.dropbox.com/referrals/foobar', 23 | 'display_name': 'Foo Bar', 24 | 'uid': 10101010, 25 | 'country': 'US', 26 | 'quota_info': { 27 | 'shared': 138573, 28 | 'quota': 2952790016, 29 | 'normal': 157327 30 | }, 31 | 'email': 'foo@bar.com' 32 | }) 33 | 34 | def test_login(self): 35 | self.do_login() 36 | 37 | def test_partial_pipeline(self): 38 | self.do_partial_pipeline() 39 | -------------------------------------------------------------------------------- /social_core/tests/backends/test_edmodo.py: -------------------------------------------------------------------------------- 1 | import json 2 | 3 | from .oauth import OAuth2Test 4 | 5 | 6 | class EdmodoOAuth2Test(OAuth2Test): 7 | backend_path = 'social_core.backends.edmodo.EdmodoOAuth2' 8 | user_data_url = 'https://api.edmodo.com/users/me' 9 | expected_username = 'foobar12345' 10 | access_token_body = json.dumps({ 11 | 'access_token': 'foobar', 12 | 'token_type': 'bearer' 13 | }) 14 | user_data_body = json.dumps({ 15 | 'username': 'foobar12345', 16 | 'coppa_verified': False, 17 | 'first_name': 'Foo', 18 | 'last_name': 'Bar', 19 | 'premium': False, 20 | 'verified_institution_member': False, 21 | 'url': 'https://api.edmodo.com/users/12345', 22 | 'type': 'teacher', 23 | 'time_zone': None, 24 | 'end_level': None, 25 | 'start_level': None, 26 | 'locale': 'en', 27 | 'subjects': None, 28 | 'utc_offset': None, 29 | 'email': 'foo.bar@example.com', 30 | 'gender': None, 31 | 'about': None, 32 | 'user_title': None, 33 | 'id': 12345, 34 | 'avatars': { 35 | 'small': 'https://api.edmodo.com/users/12345/avatar?type=small&u=5a15xug93m53mi4ey3ck4fvkq', 36 | 'large': 'https://api.edmodo.com/users/12345/avatar?type=large&u=5a15xug93m53mi4ey3ck4fvkq' 37 | } 38 | }) 39 | 40 | def test_login(self): 41 | self.do_login() 42 | 43 | def test_partial_pipeline(self): 44 | self.do_partial_pipeline() 45 | -------------------------------------------------------------------------------- /social_core/tests/backends/test_email.py: -------------------------------------------------------------------------------- 1 | from .legacy import BaseLegacyTest 2 | 3 | 4 | class EmailTest(BaseLegacyTest): 5 | backend_path = 'social_core.backends.email.EmailAuth' 6 | expected_username = 'foo' 7 | response_body = 'email=foo@bar.com' 8 | form = """ 9 |
10 | 11 | 12 |
13 | """ 14 | 15 | def test_login(self): 16 | self.do_login() 17 | 18 | def test_partial_pipeline(self): 19 | self.do_partial_pipeline() 20 | -------------------------------------------------------------------------------- /social_core/tests/backends/test_eventbrite.py: -------------------------------------------------------------------------------- 1 | import json 2 | 3 | from .oauth import OAuth2Test 4 | 5 | 6 | class EventbriteAuth2Test(OAuth2Test): 7 | backend_path = 'social_core.backends.eventbrite.EventbriteOAuth2' 8 | user_data_url = 'https://www.eventbriteapi.com/v3/users/me' 9 | expected_username = 'sean+awesome@eventbrite.com' 10 | access_token_body = json.dumps({ 11 | 'access_token': 'foobar', 12 | 'token_type': 'bearer' 13 | }) 14 | user_data_body = json.dumps({ 15 | 'first_name': 'sean', 16 | 'last_name': 'rose', 17 | 'name': 'sean rose', 18 | 'access_token': 'YQEN5H2W2OTKQZWZMYER', 19 | 'emails': [ 20 | { 21 | 'verified': True, 22 | 'email': 'sean+awesome2@eventbrite.com', 23 | 'primary': False, 24 | }, 25 | { 26 | 'verified': True, 27 | 'email': 'sean+awesome@eventbrite.com', 28 | 'primary': True, 29 | }, 30 | ], 31 | 'token_type': 'bearer', 32 | 'image_id': None, 33 | 'is_public': False, 34 | 'id': '128559602587', 35 | }) 36 | 37 | def test_login(self): 38 | self.do_login() 39 | -------------------------------------------------------------------------------- /social_core/tests/backends/test_flat.py: -------------------------------------------------------------------------------- 1 | import json 2 | 3 | from .oauth import OAuth2Test 4 | 5 | 6 | class FlatOAuth2Test(OAuth2Test): 7 | backend_path = 'social_core.backends.flat.FlatOAuth2' 8 | user_data_url = 'https://api.flat.io/v2/me' 9 | expected_username = 'vincent' 10 | access_token_body = json.dumps({ 11 | 'access_token': 'foobar', 12 | 'token_type': 'bearer' 13 | }) 14 | user_data_body = json.dumps({ 15 | "id": "541a137946fd04d57cb2e3c0", 16 | "username": "vincent", 17 | "name": "Vincent Foo", 18 | "printableName": "Vincent Foo", 19 | "bio": "Foo bio", 20 | "instruments": [], 21 | "picture": "https://flat-prod-public.s3.amazonaws.com/00000000/a0d2cb86-ab1e-4fdb-9286-dd94aa6d386c.jpeg", 22 | "registrationDate": "2014-09-17T23:04:25.042Z", 23 | "htmlUrl": "https://flat.io/vincent", 24 | "starredScoresCount": 85, 25 | "likedScoresCount": 85, 26 | "followersCount": 183, 27 | "followingCount": 52, 28 | "ownedPublicScoresCount": 15, 29 | "isPowerUser": True 30 | }) 31 | 32 | def test_login(self): 33 | self.do_login() 34 | 35 | def test_partial_pipeline(self): 36 | self.do_partial_pipeline() -------------------------------------------------------------------------------- /social_core/tests/backends/test_flickr.py: -------------------------------------------------------------------------------- 1 | from six.moves.urllib_parse import urlencode 2 | 3 | from .oauth import OAuth1Test 4 | 5 | 6 | class FlickrOAuth1Test(OAuth1Test): 7 | backend_path = 'social_core.backends.flickr.FlickrOAuth' 8 | expected_username = 'foobar' 9 | access_token_body = urlencode({ 10 | 'oauth_token_secret': 'a-secret', 11 | 'username': 'foobar', 12 | 'oauth_token': 'foobar', 13 | 'user_nsid': '10101010@N01' 14 | }) 15 | request_token_body = urlencode({ 16 | 'oauth_token_secret': 'foobar-secret', 17 | 'oauth_token': 'foobar', 18 | 'oauth_callback_confirmed': 'true' 19 | }) 20 | 21 | def test_login(self): 22 | self.do_login() 23 | 24 | def test_partial_pipeline(self): 25 | self.do_partial_pipeline() 26 | -------------------------------------------------------------------------------- /social_core/tests/backends/test_itembase.py: -------------------------------------------------------------------------------- 1 | import json 2 | 3 | from .oauth import OAuth2Test 4 | 5 | 6 | class ItembaseOAuth2Test(OAuth2Test): 7 | backend_path = 'social_core.backends.itembase.ItembaseOAuth2' 8 | user_data_url = 'https://users.itembase.com/v1/me' 9 | expected_username = 'foobar' 10 | access_token_body = json.dumps({ 11 | "access_token": "foobar-token", 12 | "expires_in": 2592000, 13 | "token_type": "bearer", 14 | "scope": "user.minimal", 15 | "refresh_token": "foobar-refresh-token" 16 | }) 17 | user_data_body = json.dumps({ 18 | "uuid": "a4b91ee7-ec1a-49b9-afce-371dc8797749", 19 | "username": "foobar", 20 | "email": "foobar@itembase.biz", 21 | "first_name": "Foo", 22 | "middle_name": None, 23 | "last_name": "Bar", 24 | "name_format": "first middle last", 25 | "locale": "en", 26 | "preferred_currency": "EUR" 27 | }) 28 | refresh_token_body = json.dumps({ 29 | "access_token": "foobar-new-token", 30 | "expires_in": 2592000, 31 | "token_type": "bearer", 32 | "scope": "user.minimal", 33 | "refresh_token": "foobar-new-refresh-token" 34 | }) 35 | 36 | def test_login(self): 37 | self.do_login() 38 | 39 | def test_partial_pipeline(self): 40 | self.do_partial_pipeline() 41 | 42 | 43 | class ItembaseOAuth2SandboxTest(OAuth2Test): 44 | backend_path = 'social_core.backends.itembase.ItembaseOAuth2Sandbox' 45 | user_data_url = 'http://sandbox.users.itembase.io/v1/me' 46 | -------------------------------------------------------------------------------- /social_core/tests/backends/test_kakao.py: -------------------------------------------------------------------------------- 1 | import json 2 | 3 | from .oauth import OAuth2Test 4 | 5 | 6 | class KakaoOAuth2Test(OAuth2Test): 7 | backend_path = 'social_core.backends.kakao.KakaoOAuth2' 8 | user_data_url = 'https://kapi.kakao.com/v1/user/me' 9 | expected_username = 'foobar' 10 | access_token_body = json.dumps({ 11 | 'access_token': 'foobar' 12 | }) 13 | user_data_body = json.dumps({ 14 | 'id': '101010101', 15 | 'properties': { 16 | 'nickname': 'foobar', 17 | 'thumbnail_image': 'http://mud-kage.kakao.co.kr/14/dn/btqbh1AKmRf/' 18 | 'ujlHpQhxtMSbhKrBisrxe1/o.jpg', 19 | 'profile_image': 'http://mud-kage.kakao.co.kr/14/dn/btqbjCnl06Q/' 20 | 'wbMJSVAUZB7lzSImgGdsoK/o.jpg' 21 | } 22 | }) 23 | 24 | def test_login(self): 25 | self.do_login() 26 | 27 | def test_partial_pipeline(self): 28 | self.do_partial_pipeline() 29 | -------------------------------------------------------------------------------- /social_core/tests/backends/test_khanacademy.py: -------------------------------------------------------------------------------- 1 | import json 2 | 3 | from six.moves.urllib_parse import urlencode 4 | 5 | 6 | from .oauth import OAuth1Test 7 | 8 | 9 | class KhanAcademyOAuth1Test(OAuth1Test): 10 | backend_path = 'social_core.backends.khanacademy.KhanAcademyOAuth1' 11 | user_data_url = 'https://www.khanacademy.org/api/v1/user' 12 | expected_username = 'foo@bar.com' 13 | access_token_body = json.dumps({ 14 | 'access_token': 'foobar', 15 | 'token_type': 'bearer' 16 | }) 17 | request_token_body = urlencode({ 18 | 'oauth_token_secret': 'foobar-secret', 19 | 'oauth_token': 'foobar', 20 | 'oauth_callback_confirmed': 'true' 21 | }) 22 | user_data_body = json.dumps({ 23 | "email": "foo@bar.com", 24 | "user_id": "http://googleid.khanacademy.org/11111111111111", 25 | }) 26 | 27 | def test_login(self): 28 | self.do_login() 29 | 30 | def test_partial_pipeline(self): 31 | self.do_partial_pipeline() 32 | -------------------------------------------------------------------------------- /social_core/tests/backends/test_linkedin.py: -------------------------------------------------------------------------------- 1 | import json 2 | 3 | from six.moves.urllib_parse import urlencode 4 | 5 | 6 | from .oauth import OAuth1Test, OAuth2Test 7 | 8 | 9 | class BaseLinkedinTest(object): 10 | user_data_url = 'https://api.linkedin.com/v1/people/~:' \ 11 | '(first-name,id,last-name)' 12 | expected_username = 'FooBar' 13 | access_token_body = json.dumps({ 14 | 'access_token': 'foobar', 15 | 'token_type': 'bearer' 16 | }) 17 | user_data_body = json.dumps({ 18 | 'lastName': 'Bar', 19 | 'id': '1010101010', 20 | 'firstName': 'Foo' 21 | }) 22 | 23 | def test_login(self): 24 | self.do_login() 25 | 26 | def test_partial_pipeline(self): 27 | self.do_partial_pipeline() 28 | 29 | 30 | class LinkedinOAuth1Test(BaseLinkedinTest, OAuth1Test): 31 | backend_path = 'social_core.backends.linkedin.LinkedinOAuth' 32 | request_token_body = urlencode({ 33 | 'oauth_token_secret': 'foobar-secret', 34 | 'oauth_token': 'foobar', 35 | 'oauth_callback_confirmed': 'true' 36 | }) 37 | 38 | 39 | class LinkedinOAuth2Test(BaseLinkedinTest, OAuth2Test): 40 | backend_path = 'social_core.backends.linkedin.LinkedinOAuth2' 41 | 42 | 43 | class LinkedinMobileOAuth2Test(BaseLinkedinTest, OAuth2Test): 44 | backend_path = 'social_core.backends.linkedin.LinkedinMobileOAuth2' 45 | -------------------------------------------------------------------------------- /social_core/tests/backends/test_live.py: -------------------------------------------------------------------------------- 1 | import json 2 | 3 | from .oauth import OAuth2Test 4 | 5 | 6 | class LiveOAuth2Test(OAuth2Test): 7 | backend_path = 'social_core.backends.live.LiveOAuth2' 8 | user_data_url = 'https://apis.live.net/v5.0/me' 9 | expected_username = 'FooBar' 10 | access_token_body = json.dumps({ 11 | 'access_token': 'foobar', 12 | 'token_type': 'bearer' 13 | }) 14 | user_data_body = json.dumps({ 15 | 'first_name': 'Foo', 16 | 'last_name': 'Bar', 17 | 'name': 'Foo Bar', 18 | 'locale': 'en_US', 19 | 'gender': None, 20 | 'emails': { 21 | 'personal': None, 22 | 'account': 'foobar@live.com', 23 | 'business': None, 24 | 'preferred': 'foobar@live.com' 25 | }, 26 | 'link': 'https://profile.live.com/', 27 | 'updated_time': '2013-03-17T05:51:30+0000', 28 | 'id': '1010101010101010' 29 | }) 30 | 31 | def test_login(self): 32 | self.do_login() 33 | 34 | def test_partial_pipeline(self): 35 | self.do_partial_pipeline() 36 | -------------------------------------------------------------------------------- /social_core/tests/backends/test_lyft.py: -------------------------------------------------------------------------------- 1 | import json 2 | 3 | from .oauth import OAuth2Test 4 | 5 | 6 | class LyftOAuth2Test(OAuth2Test): 7 | backend_path = 'social_core.backends.lyft.LyftOAuth2' 8 | user_data_url = 'https://api.lyft.com/v1/profile' 9 | access_token_body = json.dumps({ 10 | 'access_token': 'atoken_foo', 11 | 'refresh_token': 'rtoken_bar', 12 | 'token_type': 'bearer', 13 | 'expires_in': 3600, 14 | 'scope': 'public profile rides.read rides.request', 15 | 'id': 'user_foobar' 16 | }) 17 | user_data_body = json.dumps({ 18 | 'id': 'user_foobar' 19 | }) 20 | expected_username = 'user_foobar' 21 | 22 | def test_login(self): 23 | self.do_login() 24 | 25 | def test_partial_pipeline(self): 26 | self.do_partial_pipeline() 27 | -------------------------------------------------------------------------------- /social_core/tests/backends/test_mineid.py: -------------------------------------------------------------------------------- 1 | import json 2 | 3 | from .oauth import OAuth2Test 4 | 5 | 6 | class MineIDOAuth2Test(OAuth2Test): 7 | backend_path = 'social_core.backends.mineid.MineIDOAuth2' 8 | user_data_url = 'https://www.mineid.org/api/user' 9 | expected_username = 'foo@bar.com' 10 | access_token_body = json.dumps({ 11 | 'access_token': 'foobar', 12 | 'token_type': 'bearer' 13 | }) 14 | user_data_body = json.dumps({ 15 | 'email': 'foo@bar.com', 16 | 'primary_profile': None, 17 | }) 18 | 19 | def test_login(self): 20 | self.do_login() 21 | 22 | def test_partial_pipeline(self): 23 | self.do_partial_pipeline() 24 | -------------------------------------------------------------------------------- /social_core/tests/backends/test_naver.py: -------------------------------------------------------------------------------- 1 | import json 2 | 3 | from .oauth import OAuth2Test 4 | 5 | 6 | class NaverOAuth2Test(OAuth2Test): 7 | backend_path = 'social_core.backends.naver.NaverOAuth2' 8 | user_data_url = 'https://openapi.naver.com/v1/nid/getUserProfile.xml' 9 | expected_username = 'foobar' 10 | access_token_body = json.dumps({ 11 | 'access_token': 'foobar', 12 | 'token_type': 'bearer', 13 | }) 14 | 15 | user_data_content_type = 'text/xml' 16 | user_data_body = \ 17 | '' \ 18 | '' \ 19 | '' \ 20 | '00' \ 21 | 'success' \ 22 | '' \ 23 | '' \ 24 | '' \ 25 | '' \ 26 | '' \ 27 | '' \ 28 | '' \ 29 | '' \ 30 | 'M' \ 31 | '' \ 32 | '' \ 33 | '' \ 34 | '' \ 35 | '' 36 | 37 | def test_login(self): 38 | self.do_login() 39 | 40 | def test_partial_pipeline(self): 41 | self.do_partial_pipeline() 42 | -------------------------------------------------------------------------------- /social_core/tests/backends/test_orbi.py: -------------------------------------------------------------------------------- 1 | import json 2 | 3 | from .oauth import OAuth2Test 4 | 5 | 6 | class OrbiOAuth2Test(OAuth2Test): 7 | backend_path = 'social_core.backends.orbi.OrbiOAuth2' 8 | user_data_url = 'https://login.orbi.kr/oauth/user/get' 9 | expected_username = 'foobar' 10 | access_token_body = json.dumps({ 11 | 'access_token': 'foobar', 12 | }) 13 | user_data_body = json.dumps({ 14 | 'username': 'foobar', 15 | 'first_name': 'Foo', 16 | 'last_name': 'Bar', 17 | 'name': 'Foo Bar', 18 | 19 | 'imin': '100000', 20 | 'nick': 'foobar', 21 | 'photo': 'http://s3.orbi.kr/data/member/wi/wizetdev_132894975780.jpeg', 22 | 'sex': 'M', 23 | 'birth': '1973-08-03', 24 | }) 25 | 26 | def test_login(self): 27 | self.do_login() 28 | 29 | def test_partial_pipeline(self): 30 | self.do_partial_pipeline() 31 | -------------------------------------------------------------------------------- /social_core/tests/backends/test_pinterest.py: -------------------------------------------------------------------------------- 1 | import json 2 | 3 | from .oauth import OAuth2Test 4 | 5 | 6 | class PinterestOAuth2Test(OAuth2Test): 7 | backend_path = 'social_core.backends.pinterest.PinterestOAuth2' 8 | user_data_url = 'https://api.pinterest.com/v1/me/' 9 | expected_username = 'foobar' 10 | access_token_body = json.dumps({ 11 | 'access_token': 'foobar', 12 | 'token_type': 'bearer' 13 | }) 14 | user_data_body = json.dumps({ 15 | 'id': '4788400174839062', 16 | 'first_name': 'Foo', 17 | 'last_name': 'Bar', 18 | 'username': 'foobar', 19 | }) 20 | 21 | def test_login(self): 22 | self.do_login() 23 | 24 | def test_partial_pipeline(self): 25 | self.do_partial_pipeline() 26 | 27 | 28 | class PinterestOAuth2BrokenServerResponseTest(OAuth2Test): 29 | backend_path = 'social_core.backends.pinterest.PinterestOAuth2' 30 | user_data_url = 'https://api.pinterest.com/v1/me/' 31 | expected_username = 'foobar' 32 | access_token_body = json.dumps({ 33 | 'access_token': 'foobar', 34 | 'token_type': 'bearer' 35 | }) 36 | user_data_body = json.dumps({ 37 | 'data': { 38 | 'id': '4788400174839062', 39 | 'first_name': 'Foo', 40 | 'last_name': 'Bar', 41 | 'url': 'https://www.pinterest.com/foobar/', 42 | } 43 | }) 44 | 45 | def test_login(self): 46 | self.do_login() 47 | 48 | def test_partial_pipeline(self): 49 | self.do_partial_pipeline() 50 | -------------------------------------------------------------------------------- /social_core/tests/backends/test_qiita.py: -------------------------------------------------------------------------------- 1 | import json 2 | 3 | from .oauth import OAuth2Test 4 | 5 | 6 | class QiitaOAuth2Test(OAuth2Test): 7 | backend_path = 'social_core.backends.qiita.QiitaOAuth2' 8 | user_data_url = 'https://qiita.com/api/v2/authenticated_user' 9 | expected_username = 'foobar' 10 | 11 | access_token_body = json.dumps({ 12 | 'token': 'foobar', 13 | 'token_type': 'bearer' 14 | }) 15 | 16 | user_data_body = json.dumps({ 17 | 'id': 'foobar', 18 | 'name': 'Foo Bar' 19 | }) 20 | 21 | def test_login(self): 22 | self.do_login() 23 | 24 | def test_partial_pipeline(self): 25 | self.do_partial_pipeline() 26 | -------------------------------------------------------------------------------- /social_core/tests/backends/test_quizlet.py: -------------------------------------------------------------------------------- 1 | import json 2 | 3 | from .oauth import OAuth2Test 4 | 5 | 6 | class QuizletOAuth2Test(OAuth2Test): 7 | backend_path = 'social_core.backends.quizlet.QuizletOAuth2' 8 | expected_username = 'foo_bar' 9 | 10 | access_token_body = json.dumps({ 11 | "access_token": "EE1IDxytP04tJ767GbjH7ED9PpGmYvL", 12 | "token_type": "Bearer", 13 | "expires_in": 3600, 14 | "scope": "read", 15 | 'user_id': 'foo_bar' 16 | }) 17 | 18 | def test_login(self): 19 | self.do_login() 20 | 21 | def test_partial_pipeline(self): 22 | self.do_partial_pipeline() 23 | -------------------------------------------------------------------------------- /social_core/tests/backends/test_readability.py: -------------------------------------------------------------------------------- 1 | import json 2 | 3 | from six.moves.urllib_parse import urlencode 4 | 5 | from .oauth import OAuth1Test 6 | 7 | 8 | class ReadabilityOAuth1Test(OAuth1Test): 9 | backend_path = 'social_core.backends.readability.ReadabilityOAuth' 10 | user_data_url = 'https://www.readability.com/api/rest/v1/users/_current' 11 | expected_username = 'foobar' 12 | access_token_body = json.dumps({ 13 | 'access_token': 'foobar', 14 | 'token_type': 'bearer' 15 | }) 16 | request_token_body = urlencode({ 17 | 'oauth_token_secret': 'foobar-secret', 18 | 'oauth_token': 'foobar', 19 | 'oauth_callback_confirmed': 'true' 20 | }) 21 | user_data_body = json.dumps({ 22 | 'username': 'foobar', 23 | 'first_name': 'Foo', 24 | 'last_name': 'Bar', 25 | 'has_active_subscription': False, 26 | 'tags': [], 27 | 'is_publisher': False, 28 | 'email_into_address': 'foobar+sharp@inbox.readability.com', 29 | 'kindle_email_address': None, 30 | 'avatar_url': 'https://secure.gravatar.com/avatar/' 31 | '5280f15cedf540b544eecc30fcf3027c?d=' 32 | 'https://www.readability.com/media/images/' 33 | 'avatar.png&s=36', 34 | 'date_joined': '2013-03-18 02:51:02' 35 | }) 36 | 37 | def test_login(self): 38 | self.do_login() 39 | 40 | def test_partial_pipeline(self): 41 | self.do_partial_pipeline() 42 | -------------------------------------------------------------------------------- /social_core/tests/backends/test_scistarter.py: -------------------------------------------------------------------------------- 1 | import json 2 | 3 | from httpretty import HTTPretty 4 | 5 | from ...exceptions import AuthFailed 6 | from .oauth import OAuth2Test 7 | 8 | 9 | class ScistarterOAuth2Test(OAuth2Test): 10 | backend_path = 'social_core.backends.scistarter.SciStarterOAuth2' 11 | user_data_url = 'https://scistarter.com/api/user_info' 12 | expected_username = 'foobar' 13 | access_token_body = json.dumps({ 14 | 'access_token': 'foobar', 15 | 'token_type': 'bearer' 16 | }) 17 | user_data_body = json.dumps({ 18 | 'profile_id': 42006, 19 | 'user_id': 5, 20 | 'url': 'https://scistarter.com/user/foobar', 21 | 'result': 'success', 22 | 'handle': 'foobar', 23 | 'email': 'foo@bar.com', 24 | 'first_name': 'foo', 25 | 'last_name': 'bar' 26 | }) 27 | 28 | def test_login(self): 29 | self.do_login() 30 | 31 | def test_partial_pipeline(self): 32 | self.do_partial_pipeline() 33 | -------------------------------------------------------------------------------- /social_core/tests/backends/test_sketchfab.py: -------------------------------------------------------------------------------- 1 | import json 2 | 3 | from .oauth import OAuth2Test 4 | 5 | 6 | class SketchfabOAuth2Test(OAuth2Test): 7 | backend_path = 'social_core.backends.sketchfab.SketchfabOAuth2' 8 | user_data_url = 'https://sketchfab.com/v2/users/me' 9 | expected_username = 'foobar' 10 | access_token_body = json.dumps({ 11 | 'access_token': 'foobar', 12 | 'token_type': 'bearer' 13 | }) 14 | user_data_body = json.dumps({ 15 | 'uid': '42', 16 | 'email': 'foo@bar.com', 17 | 'displayName': 'foo bar', 18 | 'username': 'foobar', 19 | 'apiToken': 'XXX' 20 | }) 21 | 22 | def test_login(self): 23 | self.do_login() 24 | 25 | def test_partial_pipeline(self): 26 | self.do_partial_pipeline() 27 | -------------------------------------------------------------------------------- /social_core/tests/backends/test_skyrock.py: -------------------------------------------------------------------------------- 1 | import json 2 | 3 | from six.moves.urllib_parse import urlencode 4 | 5 | from .oauth import OAuth1Test 6 | 7 | 8 | class SkyrockOAuth1Test(OAuth1Test): 9 | backend_path = 'social_core.backends.skyrock.SkyrockOAuth' 10 | user_data_url = 'https://api.skyrock.com/v2/user/get.json' 11 | expected_username = 'foobar' 12 | access_token_body = json.dumps({ 13 | 'access_token': 'foobar', 14 | 'token_type': 'bearer' 15 | }) 16 | request_token_body = urlencode({ 17 | 'oauth_token_secret': 'foobar-secret', 18 | 'oauth_token': 'foobar', 19 | }) 20 | user_data_body = json.dumps({ 21 | 'locale': 'en_US', 22 | 'city': '', 23 | 'has_blog': False, 24 | 'web_messager_enabled': True, 25 | 'email': 'foo@bar.com', 26 | 'username': 'foobar', 27 | 'firstname': 'Foo', 28 | 'user_url': '', 29 | 'address1': '', 30 | 'address2': '', 31 | 'has_profile': False, 32 | 'allow_messages_from': 'everybody', 33 | 'is_online': False, 34 | 'postalcode': '', 35 | 'lang': 'en', 36 | 'id_user': 10101010, 37 | 'name': 'Bar', 38 | 'gender': 0, 39 | 'avatar_url': 'http://www.skyrock.com/img/avatars/default-0.jpg', 40 | 'nb_friends': 0, 41 | 'country': 'US', 42 | 'birth_date': '1980-06-10' 43 | }) 44 | 45 | def test_login(self): 46 | self.do_login() 47 | 48 | def test_partial_pipeline(self): 49 | self.do_partial_pipeline() 50 | -------------------------------------------------------------------------------- /social_core/tests/backends/test_spotify.py: -------------------------------------------------------------------------------- 1 | import json 2 | 3 | from .oauth import OAuth2Test 4 | 5 | 6 | class SpotifyOAuth2Test(OAuth2Test): 7 | backend_path = 'social_core.backends.spotify.SpotifyOAuth2' 8 | user_data_url = 'https://api.spotify.com/v1/me' 9 | expected_username = 'foobar' 10 | access_token_body = json.dumps({ 11 | 'access_token': 'foobar', 12 | 'token_type': 'bearer' 13 | }) 14 | user_data_body = json.dumps({ 15 | 'display_name': None, 16 | 'external_urls': { 17 | 'spotify': 'https://open.spotify.com/user/foobar' 18 | }, 19 | 'followers': { 20 | 'href': None, 21 | 'total': 0 22 | }, 23 | 'href': 'https://api.spotify.com/v1/users/foobar', 24 | 'id': 'foobar', 25 | 'images': [], 26 | 'type': 'user', 27 | 'uri': 'spotify:user:foobar' 28 | }) 29 | 30 | def test_login(self): 31 | self.do_login() 32 | 33 | def test_partial_pipeline(self): 34 | self.do_partial_pipeline() 35 | -------------------------------------------------------------------------------- /social_core/tests/backends/test_stripe.py: -------------------------------------------------------------------------------- 1 | import json 2 | 3 | from .oauth import OAuth2Test 4 | 5 | 6 | class StripeOAuth2Test(OAuth2Test): 7 | backend_path = 'social_core.backends.stripe.StripeOAuth2' 8 | access_token_body = json.dumps({ 9 | 'stripe_publishable_key': 'pk_test_foobar', 10 | 'access_token': 'foobar', 11 | 'livemode': False, 12 | 'token_type': 'bearer', 13 | 'scope': 'read_only', 14 | 'refresh_token': 'rt_foobar', 15 | 'stripe_user_id': 'acct_foobar' 16 | }) 17 | expected_username = 'acct_foobar' 18 | 19 | def test_login(self): 20 | self.do_login() 21 | 22 | def test_partial_pipeline(self): 23 | self.do_partial_pipeline() 24 | -------------------------------------------------------------------------------- /social_core/tests/backends/test_taobao.py: -------------------------------------------------------------------------------- 1 | import json 2 | 3 | from .oauth import OAuth2Test 4 | 5 | 6 | class TaobaoOAuth2Test(OAuth2Test): 7 | backend_path = 'social_core.backends.taobao.TAOBAOAuth' 8 | user_data_url = 'https://eco.taobao.com/router/rest' 9 | expected_username = 'foobar' 10 | access_token_body = json.dumps({ 11 | 'access_token': 'foobar', 12 | 'token_type': 'bearer' 13 | }) 14 | user_data_body = json.dumps({ 15 | 'w2_expires_in': 0, 16 | 'taobao_user_id': '1', 17 | 'taobao_user_nick': 'foobar', 18 | 'w1_expires_in': 1800, 19 | 're_expires_in': 0, 20 | 'r2_expires_in': 0, 21 | 'expires_in': 86400, 22 | 'r1_expires_in': 1800 23 | }) 24 | 25 | def test_login(self): 26 | self.do_login() 27 | 28 | def test_partial_pipeline(self): 29 | self.do_partial_pipeline() 30 | -------------------------------------------------------------------------------- /social_core/tests/backends/test_thisismyjam.py: -------------------------------------------------------------------------------- 1 | import json 2 | 3 | from six.moves.urllib_parse import urlencode 4 | 5 | from .oauth import OAuth1Test 6 | 7 | 8 | class ThisIsMyJameOAuth1Test(OAuth1Test): 9 | backend_path = 'social_core.backends.thisismyjam.ThisIsMyJamOAuth1' 10 | user_data_url = 'http://api.thisismyjam.com/1/verify.json' 11 | expected_username = 'foobar' 12 | access_token_body = json.dumps({ 13 | 'access_token': 'foobar', 14 | 'token_type': 'bearer' 15 | }) 16 | request_token_body = urlencode({ 17 | 'oauth_token_secret': 'foobar-secret', 18 | 'oauth_token': 'foobar', 19 | 'oauth_callback_confirmed': 'true' 20 | }) 21 | user_data_body = json.dumps({ 22 | 'id': 10101010, 23 | 'person': { 24 | 'name': 'foobar', 25 | 'fullname': 'Foo Bar' 26 | } 27 | }) 28 | 29 | def test_login(self): 30 | self.do_login() 31 | 32 | def test_partial_pipeline(self): 33 | self.do_partial_pipeline() 34 | -------------------------------------------------------------------------------- /social_core/tests/backends/test_twitch.py: -------------------------------------------------------------------------------- 1 | import json 2 | from .oauth import OAuth2Test 3 | 4 | 5 | class TwitchOAuth2Test(OAuth2Test): 6 | backend_path = 'social_core.backends.twitch.TwitchOAuth2' 7 | user_data_url = 'https://api.twitch.tv/kraken/user/' 8 | expected_username = 'test_user1' 9 | access_token_body = json.dumps({ 10 | 'access_token': 'foobar', 11 | }) 12 | user_data_body = json.dumps({ 13 | 'type': 'user', 14 | 'name': 'test_user1', 15 | 'created_at': '2011-06-03T17:49:19Z', 16 | 'updated_at': '2012-06-18T17:19:57Z', 17 | '_links': { 18 | 'self': 'https://api.twitch.tv/kraken/users/test_user1' 19 | }, 20 | 'logo': 'http://static-cdn.jtvnw.net/jtv_user_pictures/' 21 | 'test_user1-profile_image-62e8318af864d6d7-300x300.jpeg', 22 | '_id': 22761313, 23 | 'display_name': 'test_user1', 24 | 'email': 'asdf@asdf.com', 25 | 'partnered': True, 26 | 'bio': 'test bio woo I\'m a test user' 27 | }) 28 | 29 | def test_login(self): 30 | self.do_login() 31 | 32 | def test_partial_pipeline(self): 33 | self.do_partial_pipeline() 34 | -------------------------------------------------------------------------------- /social_core/tests/backends/test_uber.py: -------------------------------------------------------------------------------- 1 | import json 2 | 3 | from httpretty import HTTPretty 4 | 5 | from six.moves.urllib_parse import urlencode 6 | 7 | from ...exceptions import AuthForbidden 8 | from .oauth import OAuth1Test, OAuth2Test 9 | 10 | 11 | class UberOAuth2Test(OAuth2Test): 12 | user_data_url = 'https://api.uber.com/v1/me' 13 | backend_path = 'social_core.backends.uber.UberOAuth2' 14 | expected_username = 'foo@bar.com' 15 | 16 | user_data_body = json.dumps({ 17 | "first_name": "Foo", 18 | "last_name": "Bar", 19 | "email": "foo@bar.com", 20 | "picture": "https://", 21 | "promo_code": "barfoo", 22 | "uuid": "91d81273-45c2-4b57-8124-d0165f8240c0" 23 | }) 24 | 25 | access_token_body = json.dumps({ 26 | "access_token": "EE1IDxytP04tJ767GbjH7ED9PpGmYvL", 27 | "token_type": "Bearer", 28 | "expires_in": 2592000, 29 | "refresh_token": "Zx8fJ8qdSRRseIVlsGgtgQ4wnZBehr", 30 | "scope": "profile history request" 31 | }) 32 | 33 | def test_login(self): 34 | self.do_login() 35 | 36 | def test_partial_pipeline(self): 37 | self.do_partial_pipeline() 38 | -------------------------------------------------------------------------------- /social_core/tests/backends/test_udata.py: -------------------------------------------------------------------------------- 1 | import json 2 | 3 | from six.moves.urllib_parse import urlencode 4 | 5 | from .oauth import OAuth2Test 6 | 7 | 8 | class DatagouvfrOAuth2Test(OAuth2Test): 9 | backend_path = 'social_core.backends.udata.DatagouvfrOAuth2' 10 | user_data_url = 'https://www.data.gouv.fr/api/1/me/' 11 | expected_username = 'foobar' 12 | access_token_body = json.dumps({ 13 | 'access_token': 'foobar', 14 | 'token_type': 'bearer', 15 | 'first_name': 'foobar', 16 | 'email': 'foobar@example.com' 17 | }) 18 | request_token_body = urlencode({ 19 | 'oauth_token_secret': 'foobar-secret', 20 | 'oauth_token': 'foobar', 21 | 'oauth_callback_confirmed': 'true' 22 | }) 23 | user_data_body = json.dumps({}) 24 | 25 | def test_login(self): 26 | self.do_login() 27 | 28 | def test_partial_pipeline(self): 29 | self.do_partial_pipeline() 30 | -------------------------------------------------------------------------------- /social_core/tests/backends/test_username.py: -------------------------------------------------------------------------------- 1 | from .legacy import BaseLegacyTest 2 | 3 | 4 | class UsernameTest(BaseLegacyTest): 5 | backend_path = 'social_core.backends.username.UsernameAuth' 6 | expected_username = 'foobar' 7 | response_body = 'username=foobar' 8 | form = """ 9 |
10 | 11 | 12 |
13 | """ 14 | 15 | def test_login(self): 16 | self.do_login() 17 | 18 | def test_partial_pipeline(self): 19 | self.do_partial_pipeline() 20 | -------------------------------------------------------------------------------- /social_core/tests/backends/test_vk.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | from __future__ import unicode_literals 3 | 4 | import json 5 | 6 | from .oauth import OAuth2Test 7 | 8 | 9 | class VKOAuth2Test(OAuth2Test): 10 | backend_path = 'social_core.backends.vk.VKOAuth2' 11 | user_data_url = 'https://api.vk.com/method/users.get' 12 | expected_username = 'durov' 13 | access_token_body = json.dumps({ 14 | 'access_token': 'foobar', 15 | 'token_type': 'bearer' 16 | }) 17 | user_data_body = json.dumps({ 18 | 'response': [{ 19 | 'uid': '1', 20 | 'first_name': 'Павел', 21 | 'last_name': 'Дуров', 22 | 'screen_name': 'durov', 23 | 'nickname': '', 24 | 'photo': "http:\/\/cs7003.vk.me\/v7003815\/22a1\/xgG9fb-IJ3Y.jpg" 25 | }] 26 | }) 27 | 28 | def test_login(self): 29 | self.do_login() 30 | 31 | def test_partial_pipeline(self): 32 | self.do_partial_pipeline() 33 | -------------------------------------------------------------------------------- /social_core/tests/backends/test_wunderlist.py: -------------------------------------------------------------------------------- 1 | import json 2 | 3 | from .oauth import OAuth2Test 4 | 5 | 6 | class WunderlistOAuth2Test(OAuth2Test): 7 | backend_path = 'social_core.backends.wunderlist.WunderlistOAuth2' 8 | user_data_url = 'https://a.wunderlist.com/api/v1/user' 9 | expected_username = '12345' 10 | access_token_body = json.dumps({ 11 | 'access_token': 'foobar-token', 12 | 'token_type': 'foobar'}) 13 | user_data_body = json.dumps({ 14 | 'created_at': '2015-01-21T00:56:51.442Z', 15 | 'email': 'foo@bar.com', 16 | 'id': 12345, 17 | 'name': 'foobar', 18 | 'revision': 1, 19 | 'type': 'user', 20 | 'updated_at': '2015-01-21T00:56:51.442Z'}) 21 | 22 | def test_login(self): 23 | self.do_login() 24 | 25 | def test_partial_pipeline(self): 26 | self.do_partial_pipeline() 27 | -------------------------------------------------------------------------------- /social_core/tests/backends/test_yandex.py: -------------------------------------------------------------------------------- 1 | import json 2 | 3 | from .oauth import OAuth2Test 4 | 5 | 6 | class YandexOAuth2Test(OAuth2Test): 7 | backend_path = 'social_core.backends.yandex.YandexOAuth2' 8 | user_data_url = 'https://login.yandex.ru/info' 9 | expected_username = 'foobar' 10 | access_token_body = json.dumps({ 11 | 'access_token': 'foobar', 12 | 'token_type': 'bearer' 13 | }) 14 | user_data_body = json.dumps({ 15 | 'display_name': 'foobar', 16 | 'real_name': 'Foo Bar', 17 | 'sex': None, 18 | 'id': '101010101', 19 | 'default_email': 'foobar@yandex.com', 20 | 'emails': ['foobar@yandex.com'] 21 | }) 22 | 23 | def test_login(self): 24 | self.do_login() 25 | 26 | def test_partial_pipeline(self): 27 | self.do_partial_pipeline() 28 | -------------------------------------------------------------------------------- /social_core/tests/backends/test_zotero.py: -------------------------------------------------------------------------------- 1 | from six.moves.urllib_parse import urlencode 2 | 3 | from .oauth import OAuth1Test 4 | 5 | 6 | class ZoteroOAuth1Test(OAuth1Test): 7 | backend_path = 'social_core.backends.zotero.ZoteroOAuth' 8 | expected_username = 'FooBar' 9 | access_token_body = urlencode({ 10 | 'oauth_token': 'foobar', 11 | 'oauth_token_secret': 'rodgsNDK4hLJU1504Atk131G', 12 | 'userID': '123456_abcdef', 13 | 'username': 'FooBar' 14 | }) 15 | request_token_body = urlencode({ 16 | 'oauth_token_secret': 'foobar-secret', 17 | 'oauth_token': 'foobar', 18 | 'oauth_callback_confirmed': 'true' 19 | }) 20 | 21 | def test_login(self): 22 | self.do_login() 23 | 24 | def test_partial_pipeline(self): 25 | self.do_partial_pipeline() 26 | -------------------------------------------------------------------------------- /social_core/tests/pipeline.py: -------------------------------------------------------------------------------- 1 | from ..pipeline.partial import partial 2 | 3 | 4 | @partial 5 | def ask_for_password(strategy, *args, **kwargs): 6 | if strategy.session_get('password'): 7 | return {'password': strategy.session_get('password')} 8 | else: 9 | return strategy.redirect(strategy.build_absolute_uri('/password')) 10 | 11 | 12 | @partial 13 | def ask_for_slug(strategy, *args, **kwargs): 14 | if strategy.session_get('slug'): 15 | return {'slug': strategy.session_get('slug')} 16 | else: 17 | return strategy.redirect(strategy.build_absolute_uri('/slug')) 18 | 19 | 20 | def set_password(strategy, user, *args, **kwargs): 21 | user.set_password(kwargs['password']) 22 | 23 | 24 | def set_slug(strategy, user, *args, **kwargs): 25 | user.slug = kwargs['slug'] 26 | 27 | 28 | def remove_user(strategy, user, *args, **kwargs): 29 | return {'user': None} 30 | 31 | 32 | @partial 33 | def set_user_from_kwargs(strategy, *args, **kwargs): 34 | if strategy.session_get('attribute'): 35 | kwargs['user'].id 36 | else: 37 | return strategy.redirect(strategy.build_absolute_uri('/attribute')) 38 | 39 | 40 | @partial 41 | def set_user_from_args(strategy, user, *args, **kwargs): 42 | if strategy.session_get('attribute'): 43 | user.id 44 | else: 45 | return strategy.redirect(strategy.build_absolute_uri('/attribute')) 46 | -------------------------------------------------------------------------------- /templates/search/users_text.txt: -------------------------------------------------------------------------------- 1 | {{ object.username }} 2 | {{ object.name }} 3 | -------------------------------------------------------------------------------- /web/.gitignore: -------------------------------------------------------------------------------- 1 | settings_local.py 2 | -------------------------------------------------------------------------------- /web/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/harvardfly/network_anomaly_detection/88f37dc53defb6a424f7f3124ccabc31eb9c274e/web/__init__.py -------------------------------------------------------------------------------- /web/asgi.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | # -*- coding:utf-8 -*- 3 | 4 | import os 5 | import sys 6 | import django 7 | from channels.routing import get_default_application 8 | 9 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "web.settings_local") 10 | django.setup() 11 | application = get_default_application() 12 | -------------------------------------------------------------------------------- /web/routing.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | # -*- coding:utf-8 -*- 3 | 4 | from django.urls import path 5 | from channels.auth import AuthMiddlewareStack 6 | from channels.routing import ProtocolTypeRouter, URLRouter 7 | from channels.security.websocket import AllowedHostsOriginValidator 8 | 9 | from messager.consumers import MessagesConsumer 10 | from notifications.consumers import NotificationsConsumer 11 | 12 | # self.scope['type']获取协议类型 13 | # self.scope['url_route']['kwargs']['username']获取url中关键字参数 14 | # channels routing是scope级别的,一个连接只能由一个consumer接收和处理 15 | application = ProtocolTypeRouter({ 16 | # 普通的HTTP请求不需要我们手动在这里添加,框架会自动加载 17 | 'websocket': AllowedHostsOriginValidator( 18 | AuthMiddlewareStack( 19 | URLRouter([ 20 | path('ws/notifications/', NotificationsConsumer), 21 | path('ws//', MessagesConsumer), 22 | ]) 23 | ) 24 | ) 25 | }) 26 | 27 | """ 28 | OriginValidator或AllowedHostsOriginValidator可以防止通过WebSocket进行CSRF攻击 29 | OriginValidator需要手动添加允许访问的源站,如: 30 | from channels.security.websocket import OriginValidator 31 | 32 | application = ProtocolTypeRouter({ 33 | 'websocket': OriginValidator( 34 | AuthMiddlewareStack( 35 | URLRouter([ 36 | ... 37 | ]) 38 | ), 39 | [".imooc.com", "http://.imooc.com:80", "http://muke.site.com"] 40 | ) 41 | }) 42 | 使用AllowedHostsOriginValidator,允许的访问的源站与settings.py文件中的ALLOWED_HOSTS相同 43 | AuthMiddlewareStack用于WebSocket认证,集成了CookieMiddleware, SessionMiddleware, 44 | AuthMiddleware, 兼容Django认证系统 45 | """ 46 | -------------------------------------------------------------------------------- /web/settings_local.py.example: -------------------------------------------------------------------------------- 1 | """ 2 | 本地开发的配置文件 3 | """ 4 | from web.settings import * 5 | 6 | DEBUG = True 7 | 8 | DATABASES = { 9 | "default": { 10 | "ENGINE": "django.db.backends.mysql", 11 | "HOST": "127.0.0.1", 12 | "USER": "root", 13 | "NAME": "test_cpass", 14 | "PASSWORD": "password", 15 | "PORT": "", 16 | }, 17 | } 18 | 19 | INSTALLED_APPS += [ 20 | 'django_extensions', 21 | # 'debug_toolbar', 22 | # 'debug_test', 23 | ] 24 | 25 | MIDDLEWARE += [ 26 | # 'debug_toolbar.middleware.DebugToolbarMiddleware', 27 | ] 28 | 29 | # redis cache server 30 | REDIS_CACHE_SETTINGS = { 31 | 'host': "127.0.0.1", 32 | 'port': 6379, 33 | 'auth': None, 34 | 'db': 10 35 | } 36 | 37 | # celery settings 38 | CELERY_SETTINGS = { 39 | 'namespace': 'test_cpass', 40 | 'broker_url': 'redis://localhost:6379/0', 41 | 'result_backend': 'redis://localhost:6379/1' 42 | } 43 | 44 | RAVEN_CONFIG = { 45 | 'dsn': 'http://', 46 | } 47 | 48 | SOCIAL_AUTH_WEIBO_KEY = '' 49 | SOCIAL_AUTH_WEIBO_SECRET = '' 50 | SOCIAL_AUTH_LOGIN_REDIRECT_URL = '' 51 | -------------------------------------------------------------------------------- /web/urls.py: -------------------------------------------------------------------------------- 1 | """ 2 | 3 | The `urlpatterns` list routes URLs to views. For more information please see: 4 | https://docs.djangoproject.com/en/1.8/topics/http/urls/ 5 | Examples: 6 | Function views 7 | 1. Add an import: from my_app import views 8 | 2. Add a URL to urlpatterns: url(r'^$', views.home, name='home') 9 | Class-based views 10 | 1. Add an import: from other_app.views import Home 11 | 2. Add a URL to urlpatterns: url(r'^$', Home.as_view(), name='home') 12 | Including another URLconf 13 | 1. Add an import: from blog import urls as blog_urls 14 | 2. Add a URL to urlpatterns: url(r'^blog/', include(blog_urls)) 15 | """ 16 | from django.conf.urls import include, url 17 | from django.contrib import admin 18 | 19 | # from django.conf import settings 20 | 21 | urlpatterns = [ 22 | url(r'^admin/', admin.site.urls), 23 | url(r'^api_v1/', include('web.urls_api_v1')), 24 | # namespace="polls" django2的一个坑 25 | ] 26 | -------------------------------------------------------------------------------- /web/wsgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | WSGI config for ccnu_resource project. 3 | 4 | It exposes the WSGI callable as a module-level variable named ``application``. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/1.11/howto/deployment/wsgi/ 8 | """ 9 | 10 | import os 11 | 12 | from django.core.wsgi import get_wsgi_application 13 | 14 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "web.settings_local") 15 | 16 | application = get_wsgi_application() 17 | --------------------------------------------------------------------------------