Add javascript login function allow service A to log user to service B via javascript
CORS need to be correctly configured if not this can lead to security issues. Please do not put Access-Control-Allow-Origin: "*". You can use django-cors-headers to properly configure CORS
This commit is contained in:
parent
ee987f6d00
commit
9df1cd2e31
3 changed files with 149 additions and 25 deletions
53
cas_server/static/cas_server/cas.js
Normal file
53
cas_server/static/cas_server/cas.js
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
function cas_login(cas_server_login, service, login_service){
|
||||||
|
url = cas_server_login + '?service=' + encodeURIComponent(service);
|
||||||
|
$.ajax({
|
||||||
|
type: 'GET',
|
||||||
|
url:url,
|
||||||
|
beforeSend: function (request) {
|
||||||
|
request.setRequestHeader("X-AJAX", "1");
|
||||||
|
},
|
||||||
|
xhrFields: {
|
||||||
|
withCredentials: true
|
||||||
|
},
|
||||||
|
success: function(data, textStatus, request){
|
||||||
|
if(data.status == 'success'){
|
||||||
|
$.ajax({
|
||||||
|
type: 'GET',
|
||||||
|
url: data.url,
|
||||||
|
xhrFields: {
|
||||||
|
withCredentials: true
|
||||||
|
},
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
if(data.detail == "login required"){
|
||||||
|
window.location.href = cas_server_login + '?service=' + encodeURIComponent(login_service);
|
||||||
|
} else {
|
||||||
|
alert('error: ' + data.messages[1].message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
error: function (request, textStatus, errorThrown) {},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function cas_logout(cas_server_logout){
|
||||||
|
$.ajax({
|
||||||
|
type: 'GET',
|
||||||
|
url:cas_server_logout,
|
||||||
|
beforeSend: function (request) {
|
||||||
|
request.setRequestHeader("X-AJAX", "1");
|
||||||
|
},
|
||||||
|
xhrFields: {
|
||||||
|
withCredentials: true
|
||||||
|
},
|
||||||
|
error: function (request, textStatus, errorThrown) {},
|
||||||
|
success: function(data, textStatus, request){
|
||||||
|
if(data.status == 'error'){
|
||||||
|
alert('error: ' + data.messages[1].message);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -14,11 +14,12 @@ from .default_settings import settings
|
||||||
|
|
||||||
from django.utils.importlib import import_module
|
from django.utils.importlib import import_module
|
||||||
from django.core.urlresolvers import reverse
|
from django.core.urlresolvers import reverse
|
||||||
from django.http import HttpResponseRedirect
|
from django.http import HttpResponseRedirect, HttpResponse
|
||||||
|
from django.contrib import messages
|
||||||
|
|
||||||
import random
|
import random
|
||||||
import string
|
import string
|
||||||
|
import json
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from urlparse import urlparse, urlunparse, parse_qsl
|
from urlparse import urlparse, urlunparse, parse_qsl
|
||||||
|
@ -27,6 +28,13 @@ except ImportError:
|
||||||
from urllib.parse import urlparse, urlunparse, parse_qsl, urlencode
|
from urllib.parse import urlparse, urlunparse, parse_qsl, urlencode
|
||||||
|
|
||||||
|
|
||||||
|
def JsonResponse(request, data):
|
||||||
|
data["messages"] = []
|
||||||
|
for msg in messages.get_messages(request):
|
||||||
|
data["messages"].append({'message': msg.message, 'level': msg.level_tag})
|
||||||
|
return HttpResponse(json.dumps(data), content_type="application/json")
|
||||||
|
|
||||||
|
|
||||||
def import_attr(path):
|
def import_attr(path):
|
||||||
"""transform a python module.attr path to the attr"""
|
"""transform a python module.attr path to the attr"""
|
||||||
if not isinstance(path, str):
|
if not isinstance(path, str):
|
||||||
|
@ -42,6 +50,12 @@ def redirect_params(url_name, params=None):
|
||||||
return HttpResponseRedirect(url + "?%s" % params)
|
return HttpResponseRedirect(url + "?%s" % params)
|
||||||
|
|
||||||
|
|
||||||
|
def reverse_params(url_name, params=None, **kwargs):
|
||||||
|
url = reverse(url_name, **kwargs)
|
||||||
|
params = urlencode(params if params else {})
|
||||||
|
return url + "?%s" % params
|
||||||
|
|
||||||
|
|
||||||
def update_url(url, params):
|
def update_url(url, params):
|
||||||
"""update params in the `url` query string"""
|
"""update params in the `url` query string"""
|
||||||
if not isinstance(url, bytes):
|
if not isinstance(url, bytes):
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
from .default_settings import settings
|
from .default_settings import settings
|
||||||
|
|
||||||
from django.shortcuts import render, redirect
|
from django.shortcuts import render, redirect
|
||||||
|
from django.core.urlresolvers import reverse
|
||||||
from django.http import HttpResponse, HttpResponseRedirect
|
from django.http import HttpResponse, HttpResponseRedirect
|
||||||
from django.contrib import messages
|
from django.contrib import messages
|
||||||
from django.utils.decorators import method_decorator
|
from django.utils.decorators import method_decorator
|
||||||
|
@ -30,6 +31,7 @@ import cas_server.utils as utils
|
||||||
import cas_server.forms as forms
|
import cas_server.forms as forms
|
||||||
import cas_server.models as models
|
import cas_server.models as models
|
||||||
|
|
||||||
|
from utils import JsonResponse
|
||||||
from .models import ServiceTicket, ProxyTicket, ProxyGrantingTicket
|
from .models import ServiceTicket, ProxyTicket, ProxyGrantingTicket
|
||||||
from .models import ServicePattern
|
from .models import ServicePattern
|
||||||
|
|
||||||
|
@ -93,6 +95,7 @@ class LogoutView(View, LogoutMixin):
|
||||||
self.request = request
|
self.request = request
|
||||||
self.service = request.GET.get('service')
|
self.service = request.GET.get('service')
|
||||||
self.url = request.GET.get('url')
|
self.url = request.GET.get('url')
|
||||||
|
self.ajax = 'HTTP_X_AJAX' in request.META
|
||||||
|
|
||||||
def get(self, request, *args, **kwargs):
|
def get(self, request, *args, **kwargs):
|
||||||
"""methode called on GET request on this view"""
|
"""methode called on GET request on this view"""
|
||||||
|
@ -108,11 +111,19 @@ class LogoutView(View, LogoutMixin):
|
||||||
# else redirect to login page
|
# else redirect to login page
|
||||||
else:
|
else:
|
||||||
if settings.CAS_REDIRECT_TO_LOGIN_AFTER_LOGOUT:
|
if settings.CAS_REDIRECT_TO_LOGIN_AFTER_LOGOUT:
|
||||||
|
|
||||||
messages.add_message(request, messages.SUCCESS, _(u'Successfully logout'))
|
messages.add_message(request, messages.SUCCESS, _(u'Successfully logout'))
|
||||||
return redirect("cas_server:login")
|
if self.ajax:
|
||||||
|
url = reverse("cas_server:login")
|
||||||
|
data = {'status': 'success', 'detail': 'logout', 'url': url}
|
||||||
|
return JsonResponse(request, data)
|
||||||
|
else:
|
||||||
|
return redirect("cas_server:login")
|
||||||
else:
|
else:
|
||||||
return render(request, settings.CAS_LOGOUT_TEMPLATE)
|
if self.ajax:
|
||||||
|
data = {'status': 'success', 'detail': 'logout'}
|
||||||
|
return JsonResponse(request, data)
|
||||||
|
else:
|
||||||
|
return render(request, settings.CAS_LOGOUT_TEMPLATE)
|
||||||
|
|
||||||
|
|
||||||
class LoginView(View, LogoutMixin):
|
class LoginView(View, LogoutMixin):
|
||||||
|
@ -129,6 +140,7 @@ class LoginView(View, LogoutMixin):
|
||||||
renew = None
|
renew = None
|
||||||
gateway = None
|
gateway = None
|
||||||
method = None
|
method = None
|
||||||
|
ajax = None
|
||||||
|
|
||||||
renewed = False
|
renewed = False
|
||||||
warned = False
|
warned = False
|
||||||
|
@ -146,6 +158,7 @@ class LoginView(View, LogoutMixin):
|
||||||
self.renew = True if request.POST.get('renew') else False
|
self.renew = True if request.POST.get('renew') else False
|
||||||
self.gateway = request.POST.get('gateway')
|
self.gateway = request.POST.get('gateway')
|
||||||
self.method = request.POST.get('method')
|
self.method = request.POST.get('method')
|
||||||
|
self.ajax = 'HTTP_X_AJAX' in request.META
|
||||||
|
|
||||||
def check_lt(self):
|
def check_lt(self):
|
||||||
# save LT for later check
|
# save LT for later check
|
||||||
|
@ -223,6 +236,7 @@ class LoginView(View, LogoutMixin):
|
||||||
self.renew = True if request.GET.get('renew') else False
|
self.renew = True if request.GET.get('renew') else False
|
||||||
self.gateway = request.GET.get('gateway')
|
self.gateway = request.GET.get('gateway')
|
||||||
self.method = request.GET.get('method')
|
self.method = request.GET.get('method')
|
||||||
|
self.ajax = 'HTTP_X_AJAX' in request.META
|
||||||
|
|
||||||
def get(self, request, *args, **kwargs):
|
def get(self, request, *args, **kwargs):
|
||||||
"""methode called on GET request on this view"""
|
"""methode called on GET request on this view"""
|
||||||
|
@ -265,40 +279,55 @@ class LoginView(View, LogoutMixin):
|
||||||
_(u"Authentication has been required by service %(name)s (%(url)s)") %
|
_(u"Authentication has been required by service %(name)s (%(url)s)") %
|
||||||
{'name': service_pattern.name, 'url': self.service}
|
{'name': service_pattern.name, 'url': self.service}
|
||||||
)
|
)
|
||||||
return render(
|
if self.ajax:
|
||||||
self.request,
|
data = {"status": "error", "detail": "confirmation needed"}
|
||||||
settings.CAS_WARN_TEMPLATE,
|
return JsonResponse(request, data)
|
||||||
{'service_ticket_url': self.user.get_service_url(
|
else:
|
||||||
self.service,
|
return render(
|
||||||
service_pattern,
|
self.request,
|
||||||
renew=self.renew
|
settings.CAS_WARN_TEMPLATE,
|
||||||
)}
|
{'service_ticket_url': self.user.get_service_url(
|
||||||
|
self.service,
|
||||||
|
service_pattern,
|
||||||
|
renew=self.renew
|
||||||
|
)}
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
# redirect, using method ?
|
# redirect, using method ?
|
||||||
list(messages.get_messages(self.request)) # clean messages before leaving django
|
list(messages.get_messages(self.request)) # clean messages before leaving django
|
||||||
return HttpResponseRedirect(
|
redirect_url = self.user.get_service_url(
|
||||||
self.user.get_service_url(self.service, service_pattern, renew=self.renew)
|
self.service,
|
||||||
|
service_pattern,
|
||||||
|
renew=self.renew
|
||||||
)
|
)
|
||||||
|
if not self.ajax:
|
||||||
|
return HttpResponseRedirect(redirect_url)
|
||||||
|
else:
|
||||||
|
data = {"status": "success", "detail": "auth", "url": redirect_url}
|
||||||
|
return JsonResponse(self.request, data)
|
||||||
except ServicePattern.DoesNotExist:
|
except ServicePattern.DoesNotExist:
|
||||||
|
error = 1
|
||||||
messages.add_message(
|
messages.add_message(
|
||||||
self.request,
|
self.request,
|
||||||
messages.ERROR,
|
messages.ERROR,
|
||||||
_(u'Service %(url)s non allowed.') % {'url': self.service}
|
_(u'Service %(url)s non allowed.') % {'url': self.service}
|
||||||
)
|
)
|
||||||
except models.BadUsername:
|
except models.BadUsername:
|
||||||
|
error = 2
|
||||||
messages.add_message(
|
messages.add_message(
|
||||||
self.request,
|
self.request,
|
||||||
messages.ERROR,
|
messages.ERROR,
|
||||||
_(u"Username non allowed")
|
_(u"Username non allowed")
|
||||||
)
|
)
|
||||||
except models.BadFilter:
|
except models.BadFilter:
|
||||||
|
error = 3
|
||||||
messages.add_message(
|
messages.add_message(
|
||||||
self.request,
|
self.request,
|
||||||
messages.ERROR,
|
messages.ERROR,
|
||||||
_(u"User charateristics non allowed")
|
_(u"User charateristics non allowed")
|
||||||
)
|
)
|
||||||
except models.UserFieldNotDefined:
|
except models.UserFieldNotDefined:
|
||||||
|
error = 4
|
||||||
messages.add_message(
|
messages.add_message(
|
||||||
self.request,
|
self.request,
|
||||||
messages.ERROR,
|
messages.ERROR,
|
||||||
|
@ -307,11 +336,19 @@ class LoginView(View, LogoutMixin):
|
||||||
)
|
)
|
||||||
|
|
||||||
# if gateway is set and auth failed redirect to the service without authentication
|
# if gateway is set and auth failed redirect to the service without authentication
|
||||||
if self.gateway:
|
if self.gateway and not self.ajax:
|
||||||
list(messages.get_messages(self.request)) # clean messages before leaving django
|
list(messages.get_messages(self.request)) # clean messages before leaving django
|
||||||
return HttpResponseRedirect(self.service)
|
return HttpResponseRedirect(self.service)
|
||||||
|
|
||||||
return render(self.request, settings.CAS_LOGGED_TEMPLATE, {'session': self.request.session})
|
if not self.ajax:
|
||||||
|
return render(
|
||||||
|
self.request,
|
||||||
|
settings.CAS_LOGGED_TEMPLATE,
|
||||||
|
{'session': self.request.session}
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
data = {"status": "error", "detail": "auth", "code": error}
|
||||||
|
return JsonResponse(self.request, data)
|
||||||
|
|
||||||
def authenticated(self):
|
def authenticated(self):
|
||||||
"""Processing authenticated users"""
|
"""Processing authenticated users"""
|
||||||
|
@ -322,24 +359,36 @@ class LoginView(View, LogoutMixin):
|
||||||
)
|
)
|
||||||
except models.User.DoesNotExist:
|
except models.User.DoesNotExist:
|
||||||
self.logout()
|
self.logout()
|
||||||
return utils.redirect_params("cas_server:login", params=self.request.GET)
|
if self.ajax:
|
||||||
|
data = {
|
||||||
|
"status": "error",
|
||||||
|
"detail": "login required",
|
||||||
|
"url": utils.reverse_params("cas_server:login", params=self.request.GET)
|
||||||
|
}
|
||||||
|
return JsonResponse(self.request, data)
|
||||||
|
else:
|
||||||
|
return utils.redirect_params("cas_server:login", params=self.request.GET)
|
||||||
|
|
||||||
# if login agains a service is self.requestest
|
# if login agains a service is self.requestest
|
||||||
if self.service:
|
if self.service:
|
||||||
return self.service_login()
|
return self.service_login()
|
||||||
else:
|
else:
|
||||||
return render(
|
if self.ajax:
|
||||||
self.request,
|
data = {"status": "success", "detail": "logged"}
|
||||||
settings.CAS_LOGGED_TEMPLATE,
|
return JsonResponse(self.request, data)
|
||||||
{'session': self.request.session}
|
else:
|
||||||
)
|
return render(
|
||||||
|
self.request,
|
||||||
|
settings.CAS_LOGGED_TEMPLATE,
|
||||||
|
{'session': self.request.session}
|
||||||
|
)
|
||||||
|
|
||||||
def not_authenticated(self):
|
def not_authenticated(self):
|
||||||
"""Processing non authenticated users"""
|
"""Processing non authenticated users"""
|
||||||
if self.service:
|
if self.service:
|
||||||
try:
|
try:
|
||||||
service_pattern = ServicePattern.validate(self.service)
|
service_pattern = ServicePattern.validate(self.service)
|
||||||
if self.gateway:
|
if self.gateway and not self.ajax:
|
||||||
# clean messages before leaving django
|
# clean messages before leaving django
|
||||||
list(messages.get_messages(self.request))
|
list(messages.get_messages(self.request))
|
||||||
return HttpResponseRedirect(self.service)
|
return HttpResponseRedirect(self.service)
|
||||||
|
@ -363,7 +412,15 @@ class LoginView(View, LogoutMixin):
|
||||||
messages.ERROR,
|
messages.ERROR,
|
||||||
_(u'Service %s non allowed') % self.service
|
_(u'Service %s non allowed') % self.service
|
||||||
)
|
)
|
||||||
return render(self.request, settings.CAS_LOGIN_TEMPLATE, {'form': self.form})
|
if self.ajax:
|
||||||
|
data = {
|
||||||
|
"status": "error",
|
||||||
|
"detail": "login required",
|
||||||
|
"url": utils.reverse_params("cas_server:login", params=self.request.GET)
|
||||||
|
}
|
||||||
|
return JsonResponse(self.request, data)
|
||||||
|
else:
|
||||||
|
return render(self.request, settings.CAS_LOGIN_TEMPLATE, {'form': self.form})
|
||||||
|
|
||||||
def common(self):
|
def common(self):
|
||||||
"""Part execute uppon GET and POST request"""
|
"""Part execute uppon GET and POST request"""
|
||||||
|
|
Loading…
Reference in a new issue