Exemplo n.º 1
0
    def create_auth(self, app_moniker, app_config):
        """
        Create application authentication configuration
        IdP, Directories, Groups
        """
        # IdP
        # The "view" operation gives us the IdP in idp -> idp_id
        scanned_idp_uuid = app_config.get('idp', {}).get('idp_id')
        if scanned_idp_uuid:
            idp_app_payload = {"app": app_moniker.uuid, "idp": scanned_idp_uuid}
            idp_app_resp = self.post('mgmt-pop/appidp', json=idp_app_payload)
            logging.info("IdP-app association response: %s %s" % (idp_app_resp.status_code, idp_app_resp.text))

        # Directory
        # The view operation gives us the directories in directories[] -> uuid_url
        scanned_directories = app_config.get('directories', [])
        app_directories_payload = {"data": [{"apps": [app_moniker.uuid], "directories": scanned_directories}]}
        app_directories_resp = self.post('mgmt-pop/appdirectories', json=app_directories_payload)
        logging.info(
            "App directories association response: %s %s" %
            (app_directories_resp.status_code, app_directories_resp.text)
        )
        if app_directories_resp.status_code != 200:
            cli.exit(2)
        # Groups
        if len(app_config.get('groups', [])) > 0:
            app_groups_payload = {'data': [{'apps': [app_moniker.uuid], 'groups': app_config.get('groups', [])}]}
            app_groups_resp = self.post('mgmt-pop/appgroups', json=app_groups_payload)
            if app_groups_resp.status_code != 200:
                cli.exit(2)
        else:
            logging.debug("No group set")
Exemplo n.º 2
0
    def create(self, raw_app_config):
        """
        Create a new EAA application configuration.
        :param app_config: configuration as JSON string

        Note: the portal use the POST to create a new app with a minimal payload:
              {"app_profile":1,"app_type":1,"client_app_mode":1,"app_profile_id":"Fp3RYok1EeSE6AIy9YR0Dw",
              "name":"tes","description":"test"}
              We should do the same here
        """
        app_config = json.loads(self.parse_template(raw_app_config))
        logging.debug("Post Jinja parsing:\n%s" % json.dumps(app_config))
        app_config_create = {
            "app_profile":
            app_config.get('app_profile'),
            "app_type":
            app_config.get('app_type', ApplicationAPI.Type.Hosted.value),
            "name":
            app_config.get('name'),
            "description":
            app_config.get('description')
        }
        newapp = self.post('mgmt-pop/apps', json=app_config_create)
        logging.info("Create app core: %s %s" %
                     (newapp.status_code, newapp.text))
        if newapp.status_code != 200:
            cli.exit(2)
        newapp_config = newapp.json()
        logging.info("New app JSON:\n%s" % newapp.text)
        app_moniker = EAAItem("app://{}".format(newapp_config.get('uuid_url')))
        logging.info("UUID of the newapp: %s" % app_moniker)

        # Now we push everything else as a PUT
        self.put('mgmt-pop/apps/{applicationId}'.format(
            applicationId=app_moniker.uuid),
                 json=app_config)

        # Sub-components of the application configuration definition

        # --- Connectors
        if app_config.get('agents'):
            self.attach_connectors(app_moniker, app_config.get('agents', []))

        # IdP, Directories, Groups
        self.create_auth(app_moniker, app_config)

        # --- Access Control rules
        self.create_acl(app_moniker, app_config)

        # --- Other services
        # TODO: implement

        # URL based policies
        self.create_urlbasedpolicies(app_moniker, app_config)

        # At the end we reload the app entirely
        cli.print(json.dumps(self.load(app_moniker)))
Exemplo n.º 3
0
 def update(self, app_moniker, app_config):
     """
     Update an existing EAA application configuration.
     """
     update = self.put('mgmt-pop/apps/{applicationId}'.format(
         applicationId=app_moniker.uuid),
                       json=app_config)
     logging.info("Update app response: %s" % update.status_code)
     logging.info("Update app response: %s" % update.text)
     if update.status_code != 200:
         cli.exit(2)
Exemplo n.º 4
0
    def swap(self, old_con_id, new_con_id, dryrun=False):
        """
        Replace an EAA connector with another in:
        - application
        - directory

        Args:
            old_con_id (EAAItem): Existing connector to be replaced
            new_con_id (EAAItem): New connector to attach on the applications and directories
            dryrun (bool, optional): Enable dry run. Defaults to False.
        """
        infos_by_conid = {}
        old_con = EAAItem(old_con_id)
        new_con = EAAItem(new_con_id)
        for c in [old_con, new_con]:
            connector_info = self.load(c)
            if not connector_info:
                cli.print_error("EAA connector %s not found." % c)
                cli.print_error("Please check with command 'akamai eaa connector'.")
                cli.exit(2)
            # Save the details for better
            infos_by_conid[c] = connector_info
        app_api = ApplicationAPI(self._config)
        app_processed = 0
        cli.header("#Operation,connector-id,connector-name,app-id,app-name")
        for app_using_old_con, app_name, app_host in self.findappbyconnector(old_con):
            if dryrun:
                cli.print("DRYRUN +,%s,%s,%s,%s" % (
                    new_con, infos_by_conid[new_con].get('name'),
                    app_using_old_con, app_name))
                cli.print("DRYRUN -,%s,%s,%s,%s" % (
                    old_con, infos_by_conid[old_con].get('name'),
                    app_using_old_con, app_name))
            else:
                app_api.attach_connectors(app_using_old_con, [{'uuid_url': new_con.uuid}])
                cli.print("+,%s,%s,%s,%s" % (
                    new_con, infos_by_conid[new_con].get('name'),
                    app_using_old_con, app_name))
                app_api.detach_connectors(app_using_old_con, [{'uuid_url': old_con.uuid}])
                cli.print("-,%s,%s,%s,%s" % (
                    old_con, infos_by_conid[old_con].get('name'),
                    app_using_old_con, app_name))
            app_processed += 1
        if app_processed == 0:
            cli.footer("Connector %s is not used by any application." % old_con_id)
            cli.footer("Check with command 'akamai eaa connector %s apps'" % old_con_id)
        else:
            cli.footer("Connector swapped in %s application(s)." % app_processed)
            cli.footer("Updated application(s) is/are marked as ready to deploy")
Exemplo n.º 5
0
 def detach_connectors(self, app_moniker, connectors):
     """
     Detach connector/s to an application.
     Payload is different from attach above:
     {"agents":["cht3_GEjQWyMW9LEk7KQfg"]}
     """
     logging.info("Detaching {} connectors...".format(len(connectors)))
     api_resp = self.post(
         'mgmt-pop/apps/{applicationId}/agents'.format(applicationId=app_moniker.uuid),
         params={'method': 'delete'}, json={'agents': [c.get('uuid_url') for c in connectors]}
     )
     logging.info("Detach connector response: %s" % api_resp.status_code)
     logging.info("Detach connector app response: %s" % api_resp.text)
     if api_resp.status_code not in (200, 204):
         cli.print_error("Connector(s) %s were not detached from application %s [HTTP %s]" %
                         (','.join([c.get('uuid_url') for c in connectors]), app_moniker, api_resp.status_code))
         cli.print_error("use 'akamai eaa -v ...' for more info")
         cli.exit(2)
Exemplo n.º 6
0
    def rotate(self):
        """
        Update an existing certificate.
        """
        cert_moniker = EAAItem(self._config.certificate_id)
        cli.print("Rotating certificate %s..." % cert_moniker.uuid)
        api_url = 'mgmt-pop/certificates/{certificate_id}'.format(
            certificate_id=cert_moniker.uuid)

        get_resp = self.get(api_url)
        current_cert = get_resp.json()
        # cli.print(json.dumps(current_cert, sort_keys=True, indent=4))

        payload = {}
        payload['name'] = current_cert.get('name')
        cli.print("Certificate CN: %s (%s)" %
                  (current_cert.get('cn'), payload['name']))
        payload['cert_type'] = current_cert.get('cert_type')
        with self._config.cert as f:
            payload['cert'] = f.read()
        with self._config.key as f:
            payload['private_key'] = f.read()
        if self._config.passphrase:
            payload['password'] = self._config.passphrase
        put_resp = self.put(api_url,
                            json=payload,
                            params={
                                'expand': 'true',
                                'limit': 0
                            })
        if put_resp.status_code == 200:
            new_cert = put_resp.json()
            cli.footer(("Certificate %s updated, %s application/IdP(s) "
                        "have been marked ready for deployment.") %
                       (cert_moniker.uuid, new_cert.get('app_count')))
            if self._config.deployafter:
                self.deployafter(cert_moniker.uuid)
            else:
                cli.footer("Please deploy at your convience.")
        else:
            cli.print_error("Error rotating certificate, see response below:")
            cli.print_error(put_resp.text)
            cli.exit(2)
Exemplo n.º 7
0
    def attach_connectors(self, app_moniker, connectors):
        """
        Attach connector/s to an application.

        :param EAAItem app_moniker: Application Moniker (prefix + UUID)
        :param list connectors: Connector list, expected list item format is dict {'uuid_url': '<UUID>'}
        """
        # POST on mgmt-pop/apps/DBMcU6FwSjKa7c9sny4RLg/agents
        # Body
        # {"agents":[{"uuid_url":"cht3_GEjQWyMW9LEk7KQfg"}]}
        logging.info("Attaching {} connectors...".format(len(connectors)))
        api_resp = self.post(
            'mgmt-pop/apps/{applicationId}/agents'.format(applicationId=app_moniker.uuid),
            json={'agents': connectors}
        )
        logging.info("Attach connector response: %s" % api_resp.status_code)
        logging.info("Attach connector app response: %s" % api_resp.text)
        if api_resp.status_code not in (200, 201):
            cli.print_error("Connector(s) %s were not attached to application %s [HTTP %s]" %
                            (','.join([c.get('uuid_url') for c in connectors]), app_moniker, api_resp.status_code))
            cli.print_error("use 'akamai eaa -v ...' for more info")
            cli.exit(2)
Exemplo n.º 8
0
    def synchronize_group(self, group_uuid):
        """
        Synchronize a group within the directory

        Args:
            group_uuid (EAAItem): Group UUID e.g. grp://abcdef
        """
        """
        API call

        POST https://control.akamai.com/crux/v1/mgmt-pop/groups/16nUm7dCSyiihfCvMiHrMg/sync
        Payload: {}
        Response: {"response": "Syncing Group Sales Department"}
        """
        group = EAAItem(group_uuid)
        retry_remaining = self._config.retry + 1
        while retry_remaining > 0:
            retry_remaining -= 1
            cli.print("Synchronizing %s [retry=%s]..." %
                      (group_uuid, retry_remaining))
            resp = self.get(
                'mgmt-pop/directories/{dir_uuid}/groups/{group_uuid}'.format(
                    dir_uuid=self._directory_id, group_uuid=group.uuid))
            if resp.status_code != 200:
                logging.error("Error retrieve group info (%s)" %
                              resp.status_code)
                cli.exit(2)
            group_info = resp.json()
            if group_info.get('last_sync_time'):
                last_sync = datetime.datetime.fromisoformat(
                    group_info.get('last_sync_time'))
                delta = datetime.datetime.utcnow() - last_sync
                cli.print(
                    "Last sync of group %s was @ %s UTC (%d seconds ago)" %
                    (group_info.get('name'), last_sync, delta.total_seconds()))
                if delta.total_seconds() > self._config.mininterval:
                    sync_resp = self.post(
                        'mgmt-pop/groups/{group_uuid}/sync'.format(
                            group_uuid=group.uuid))
                    if sync_resp.status_code != 200:
                        cli.print_error(
                            "Fail to synchronize group (API response code %s)"
                            % sync_resp.status_code)
                        cli.exit(3)
                    else:
                        cli.print(
                            "Synchronization of group %s (%s) successfully requested."
                            % (group_info.get('name'), group))
                        break
                else:
                    cli.print_error(
                        "Last group sync is too recent, sync aborted. %s seconds interval is required."
                        % self._config.mininterval)
                    if retry_remaining == 0:
                        cli.exit(2)
                    else:
                        sleep_time = last_sync + datetime.timedelta(seconds=self._config.mininterval) - \
                                     datetime.datetime.utcnow()
                        cli.print(
                            "Sleeping for %s, press Control-Break to interrupt"
                            % sleep_time)
                        time.sleep(sleep_time.total_seconds())