#
# Copyright (c) 2016 NORDUnet A/S
# All rights reserved.
#
#   Redistribution and use in source and binary forms, with or
#   without modification, are permitted provided that the following
#   conditions are met:
#
#     1. Redistributions of source code must retain the above copyright
#        notice, this list of conditions and the following disclaimer.
#     2. Redistributions in binary form must reproduce the above
#        copyright notice, this list of conditions and the following
#        disclaimer in the documentation and/or other materials provided
#        with the distribution.
#     3. Neither the name of the NORDUnet nor the names of its
#        contributors may be used to endorse or promote products derived
#        from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
import re
import urlparse
from urllib import urlencode

from werkzeug import get_current_url
from werkzeug.http import parse_cookie, dump_cookie
from flask import Flask, session, current_app
from eduid_common.api.session import NoSessionDataFoundException
from eduid_common.api.utils import urlappend


class AuthnApp(Flask):
    """
    WSGI middleware that checks whether the request is authenticated,
    and in case it isn't, redirects to the authn service.
    """
    def __call__(self, environ, start_response):
        next_url = get_current_url(environ)
        next_path = list(urlparse.urlparse(next_url))[2]
        whitelist = self.config.get('NO_AUTHN_URLS', [])
        for regex in whitelist:
            m = re.match(regex, next_path)
            if m is not None:
                return super(AuthnApp, self).__call__(environ, start_response)

        with self.request_context(environ):
            try:
                if session.get('user_eppn'):
                    return super(AuthnApp, self).__call__(environ, start_response)
            except NoSessionDataFoundException:
                current_app.logger.info('Caught a NoSessionDataFoundException - forcing the user to authenticate')
                del environ['HTTP_COOKIE']  # Force relogin
                # If HTTP_COOKIE is not removed self.request_context(environ) below
                # will try to look up the Session data in the backend

        ts_url = urlappend(self.config.get('TOKEN_SERVICE_URL'), 'login')

        params = {'next': next_url}

        url_parts = list(urlparse.urlparse(ts_url))
        query = urlparse.parse_qs(url_parts[4])
        query.update(params)

        url_parts[4] = urlencode(query)
        location = urlparse.urlunparse(url_parts)

        with self.request_context(environ):
            cookie_name = self.config.get('SESSION_COOKIE_NAME')
            headers = [ ('Location', location) ]
            cookie = dump_cookie(cookie_name, session._session.token,
                                 max_age=int(self.config.get('PERMANENT_SESSION_LIFETIME')),
                                 path=self.config.get('SESSION_COOKIE_PATH'),
                                 domain=self.config.get('SESSION_COOKIE_DOMAIN'),
                                 secure=self.config.get('SESSION_COOKIE_SECURE'),
                                 httponly=self.config.get('SESSION_COOKIE_HTTPONLY'))
            session.persist()
            headers.append(('Set-Cookie', cookie))

            start_response('302 Found', headers)
            return []

@@ -1774,16 +1774,25 @@
 rent_app
+, request
 %0Afrom ed
@@ -4157,8 +4157,1268 @@
 turn %5B%5D%0A
+%0A%0Aclass UnAuthnApp(Flask):%0A    %22%22%22%0A    WSGI middleware that checks whether the request is authenticated,%0A    and in case it isn't, redirects to the authn service.%0A    %22%22%22%0A    def __call__(self, environ, start_response):%0A        next_url = get_current_url(environ)%0A%0A        with self.request_context(environ):%0A            cookie_name = self.config.get('SESSION_COOKIE_NAME', 'signup-sessid')%0A            if cookie_name not in request.cookies:%0A                cookie = dump_cookie(cookie_name, session._session.token,%0A                                     max_age=int(self.config.get('PERMANENT_SESSION_LIFETIME')),%0A                                     path=self.config.get('SESSION_COOKIE_PATH'),%0A                                     domain=self.config.get('SESSION_COOKIE_DOMAIN'),%0A                                     secure=self.config.get('SESSION_COOKIE_SECURE'),%0A                                     httponly=self.config.get('SESSION_COOKIE_HTTPONLY'))%0A                session.persist()%0A                headers = %5B ('Location', next_url) %5D%0A                headers.append(('Set-Cookie', cookie))%0A                start_response('302 Found', headers)%0A                return %5B%5D%0A        %0A        return super(UnAuthnApp, self).__call__(environ, start_response)%0A

add un-authn middleware - to set the session cookieç