import re
import weakref

import requests
from pyuri import URI
from requests import HTTPError
from six.moves.urllib.parse import urljoin

from swimlane.core.resources.app import AppAdapter
from swimlane.core.resources.usergroup import UserAdapter, GroupAdapter
from swimlane.errors import SwimlaneHTTP400Error


class Swimlane(object):
    """Swimlane API client"""

    _api_root = '/api/'

    def __init__(self, host, username, password, verify_ssl=True):
        self.host = URI(host)
        self.host.scheme = self.host.scheme or 'https'
        self.host.path = None

        self._session = requests.Session()
        self._session.verify = verify_ssl
        self._session.headers.update({
            'Content-Type': 'application/json'
        })
        self._session.auth = SwimlaneAuth(
            self,
            username,
            password
        )

        self.apps = AppAdapter(self)
        self.users = UserAdapter(self)
        self.groups = GroupAdapter(self)

        self.__settings = None
        self.__user = None

    def __repr__(self):
        return '<{cls}: {username} @ {host}>'.format(
            cls=self.__class__.__name__,
            username=self._session.auth.username,
            host=self.host
        )

    def request(self, method, api_endpoint, **kwargs):
        """Shortcut helper for sending requests to API endpoints
        
        Handles generating full API URL, session reuse and auth, and response status code checks
        
        Raises HTTPError on 4xx/5xx HTTP responses, or Swimlane400Error on 400 responses with well-formatted additional
        context information about the exception
        """
        while api_endpoint.startswith('/'):
            api_endpoint = api_endpoint[1:]

        response = self._session.request(method, urljoin(str(self.host) + self._api_root, api_endpoint), **kwargs)

        try:
            response.raise_for_status()
        except HTTPError as e:
            if e.response.status_code == 400:
                raise SwimlaneHTTP400Error(e)
            else:
                raise e

        return response

    @property
    def settings(self):
        """Retrieve and cache settings from server"""
        if not self.__settings:
            self.__settings = self.request('get', 'settings').json()
        return self.__settings

    @property
    def version(self):
        """Returns server API version"""
        return self.settings['apiVersion']

    @property
    def user(self):
        """Returns User record for authenticated user"""
        if not self.__user:
            self.__user = self.users.get(username=self._session.auth.username)
        return self.__user

    def _compare_version(self, *version_sections):
        """Return direction of Swimlane version relative to provided version sections
        
        If Swimlane version is equal to provided version, return 0
        If Swimlane version is greater than provided version, return 1
        If Swimlane version is less than provided version, return -1
        
        e.g. with Swimlane version = 2.13.2-173414
            _compare_version(2) = 0
            _compare_version(1) = 1
            _compare_version(3) = -1
            
            _compare_version(2, 13) = 0
            _compare_version(2, 12) = 1
            _compare_version(2, 14) = -1
            
            _compare_version(2, 13, 3) = -1
            
            _compare_version(2, 13, 2, 173415) = -1
        """
        sections_provided = len(version_sections)

        versions = tuple(re.findall(r'\d+', self.version)[0:sections_provided])

        return (versions > version_sections) - (versions < version_sections)


class SwimlaneAuth(object):

    def __init__(self, swimlane, username, password):
        self.username = username
        self.password = password

        self._swimlane = weakref.proxy(swimlane)
        self._login_headers = self._authenticate()

    def __call__(self, request):

        request.headers.update(self._login_headers)

        return request

    def _authenticate(self):
        """Send login request and return login token"""
        resp = self._swimlane.request('post', 'user/login', json={
            'userName': self.username,
            'password': self.password,
            'domain': ''
        })
        json_content = resp.json()

        # Check for token in response content
        token = json_content.get('token')

        if token is None:
            # Legacy cookie authentication (2.13-)
            headers = {'Cookie': ';'.join(
                ["%s=%s" % cookie for cookie in resp.cookies.items()]
            )}
        else:
            # JWT auth (2.14+)
            headers = {
                'Authorization': 'Bearer {}'.format(token)
            }

        return headers

@@ -35,16 +35,88 @@
 equests%0A
+from requests.packages.urllib3.exceptions import InsecureRequestWarning%0A
 from pyu
@@ -129,16 +129,16 @@
 ort URI%0A
-
 from req
@@ -378,16 +378,121 @@
 Error%0A%0A%0A
+# Disable insecure request warnings%0Arequests.packages.urllib3.disable_warnings(InsecureRequestWarning)%0A%0A%0A
 class Sw
@@ -742,24 +742,83 @@
 ath = None%0A%0A
+        self.__settings = None%0A        self.__user = None%0A%0A
         self
@@ -1170,32 +1170,32 @@
 erAdapter(self)%0A
+
         self.gro
@@ -1224,67 +1224,8 @@
 f)%0A%0A
-        self.__settings = None%0A        self.__user = None%0A%0A
     
@@ -4324,45 +4324,216 @@
     
-resp = self._swimlane.request('post',
+# Explicitly provide verify argument, appears to not consistently be acknowledged across versions during%0A        # initial setup for auth%0A        resp = self._swimlane.request(%0A            'post',%0A           
  'us
@@ -4546,16 +4546,28 @@
 in',
+%0A           
  json=%7B%0A
     
@@ -4562,16 +4562,20 @@
  json=%7B%0A
+    
         
@@ -4617,16 +4617,20 @@
         
+    
 'passwor
@@ -4648,16 +4648,20 @@
 ssword,%0A
+    
         
@@ -4677,33 +4677,97 @@
 in': ''%0A        
-%7D
+    %7D,%0A            verify=self._swimlane._session.verify%0A        
 )%0A        json_c

Fix possible verify_ssl error and ignore insecure requests warnings