# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
"""
User module to hold accounts related to users (admin or local) in the SMC
You can create an Admin User, enable superuser, enable/disable the account,
assign local access to engines, and change the account password for SMC or
engine access.
It is possible to fully provision an Admin User with specific permissions and
roles and initial password.
Create the admin::
admin = AdminUser.create(name='auditor', superuser=False)
.. note:: If the Admin User should have unrestricted access, set ``superuser=True`` and
skip the below sections related to adding permissions and roles.
Permissions relate to elements that the user will have access to (Policies, Engines or
AccessControlLists) and the domain where the privileges apply (default is 'Shared Domain').
Create a permission using the default domain of Shared, granting access to a specific
engine and firewall policy::
permission = Permission.create(
elements=[Engine('vm'), FirewallPolicy('VM Policy')],
role=Role('Viewer'))
Create a second permission granting access to all firewalls in the domain 'mydomain'::
domain_perm = Permission.create(
elements=[AccessControlList('ALL Firewalls')],
role=Role('Owner'),
domain=AdminDomain('mydomain'))
Add the permissions to the Admin User::
admin.add_permission([permission, domain_perm])
Set an initial password for the Admin User::
admin.change_password('Newpassword1')
.. note:: Roles are used to define what granular controls will be available to the assigned
user, such as read/read write/all. AccessControlLists encapsulate elements into a single
container for re-use.
.. seealso:: :class:`smc.administration.role.Role` and
:class:`smc.administration.access_rights.AccessControlList` for more information.
"""
from smc.base.model import Element, ElementCreator
from smc.api.exceptions import ModificationFailed
from smc.administration.access_rights import Permission
from smc.base.structs import NestedDict
from smc.base.util import element_resolver
from smc.administration.user_auth import servers
[docs]
class UserMixin(object):
"""
User Mixin class providing common operations for Admin Users and
API Clients.
"""
[docs]
def enable_disable(self):
"""
Toggle enable and disable of administrator account.
Change is committed immediately.
:raises UpdateElementFailed: failed with reason
:return: None
"""
self.update(href=self.get_relation("enable_disable"), etag=None)
[docs]
def change_password(self, password):
"""
Change user password. Change is committed immediately.
:param str password: new password
:return: None
"""
self.make_request(
ModificationFailed,
method="update",
resource="change_password",
params={"password": password},
)
[docs]
def generate_password(self):
"""
Generate a random password for this user.
:return: random password
:rtype: str
"""
pwd = self.make_request(method="update", resource="generate_password")
if "value" in pwd:
return pwd["value"][0]
[docs]
def add_permission(self, permission):
"""
Add a permission to this Admin User. A role defines permissions that
can be enabled or disabled. Elements define the target for permission
operations and can be either Access Control Lists, Engines or Policy
elements. Domain specifies where the access is granted. The Shared
Domain is default unless specific domain provided. Change is committed
at end of method call.
:param permission: permission/s to add to admin user
:type permission: list(Permission)
:raises UpdateElementFailed: failed updating admin user
:return: None
"""
if "permissions" not in self.data:
self.data["superuser"] = False
self.data["permissions"] = {"permission": []}
for p in permission:
self.data["permissions"]["permission"].append(p.data)
self.update()
@property
def permissions(self):
"""
Return each permission role mapping for this Admin User. A permission
role will have 3 fields:
* Domain
* Role (Viewer, Operator, etc)
* Elements (Engines, Policies, or ACLs)
:return: permissions as list
:rtype: list(Permission)
"""
if "permissions" in self.data:
_permissions = self.data["permissions"]["permission"]
return [Permission(**perm) for perm in _permissions]
return []
[docs]
class AdminUser(UserMixin, Element):
"""Represents an Adminitrator account on the SMC
Use the constructor to create the user.
Create an Admin::
>>> AdminUser.create(name='admin', superuser=True)
AdminUser(name=admin)
If modifications are required after you can access the admin and
make changes::
admin = AdminUser('admin')
admin.change_password('mynewpassword1')
admin.enable_disable()
Attributes available:
:ivar bool allow_sudo: is this account allowed to sudo on an engine.
:ivar bool local_admin: is the admin a local admin
:ivar bool superuser: is this account a superuser for SMC
"""
typeof = "admin_user"
[docs]
@classmethod
def create(
cls,
name,
local_admin=False,
allow_sudo=False,
superuser=False,
enabled=True,
engine_target=None,
can_use_api=True,
console_superuser=False,
allowed_to_login_in_shared=True,
auth_method=None,
comment=None,
permissions=None,
ldap_user_href=None,
ldap_group_href=None
):
"""
Create an admin user account.
.. versionadded:: 0.6.2
Added can_use_api, console_superuser, and allowed_to_login_in_shared.
Requires SMC >= SMC 6.4
:param str name: name of account
:param bool local_admin: is a local admin only
:param bool allow_sudo: allow sudo on engines
:param bool can_use_api: can log in to SMC API
:param bool console_superuser: can this user sudo via SSH/console
:param bool allowed_to_login_in_shared: can this user log in to the
shared domain
:param bool superuser: is a super administrator
:param auth_method: authentication method
:param bool enabled: is account enabled
:param list engine_target: engine to allow remote access to
:param comment: object comment
:param permissions object in case SMC admin is not superuser
:param ldap_user_href External user href to link as SMC admin
:param ldap_group_href External user href to link as SMC admin
:raises CreateElementFailed: failure creating element with reason
:return: instance with meta
:rtype: AdminUser
"""
engines = [] if engine_target is None else engine_target
json = {
"name": name,
"enabled": enabled,
"allow_sudo": allow_sudo,
"console_superuser": console_superuser,
"allowed_to_login_in_shared": allowed_to_login_in_shared,
"engine_target": engines,
"local_admin": local_admin,
"superuser": superuser,
"can_use_api": can_use_api,
"comment": comment,
"permissions": {"permission": []},
"ldap_user": ldap_user_href,
"ldap_group": ldap_group_href
}
if permissions:
for p in permissions:
json["permissions"]["permission"].append(p.data)
if auth_method:
auth_method_ref = servers.AuthenticationMethod(auth_method).href
json.update(auth_method=auth_method_ref)
return ElementCreator(cls, json)
@property
def enabled(self):
"""
Read only enabled status
:rtype: bool
"""
return self.data.get("enabled")
[docs]
def change_engine_password(self, password):
"""Change Engine password for engines on allowed
list.
:param str password: password for engine level
:raises ModificationFailed: failed setting password on engine
:return: None
"""
self.make_request(
ModificationFailed,
method="update",
resource="change_engine_password",
params={"password": password},
)
@property
def password_meta_data(self):
"""
Provides creation_date and expiration_date of the password for AdminUser,ApiClient and
WebPortalAdminUser.
:return: PasswordMetaData : PasswordMetaData contains creation_date and expiration_date.
"""
pwd_meta_data = self.make_request(resource="pwd_meta_data")
return PasswordMetaData(pwd_meta_data)
[docs]
class ApiClient(UserMixin, Element):
"""
Represents an API Client
"""
typeof = "api_client"
[docs]
@classmethod
def create(cls, name, enabled=True, superuser=True):
"""
Create a new API Client. Once client is created,
you can create a new password by::
>>> client = ApiClient.create('myclient')
>>> print(client)
ApiClient(name=myclient)
>>> client.change_password('mynewpassword')
:param str name: name of client
:param bool enabled: enable client
:param bool superuser: is superuser account
:raises CreateElementFailed: failure creating element with reason
:return: instance with meta
:rtype: ApiClient
"""
json = {"enabled": enabled, "name": name, "superuser": superuser}
return ElementCreator(cls, json)
[docs]
class WebPortalAdminUser(UserMixin, Element):
"""
This represents a Web Portal User.It is an element that defines the details of a single person
that is allowed to log on to the Web Portal,
the Browser-based service that allows users to view logs, Policy Snapshots, and reports
Create a Web Portal Admin User::
>>> WebPortalAdminUser.create(name='admin')
If modifications are required after you can access the admin and
make changes::
admin = WebPortalAdminUser('admin')
admin.change_password('mynewpassword1')
admin.enable_disable()
"""
typeof = "web_portal_user"
[docs]
@classmethod
def create(
cls,
name,
enabled=True,
granted_engine=None,
console_superuser=False,
log_service_enabled=True,
policy_service_enabled=True,
report_service_enabled=True,
show_inspection_policy=True,
show_main_policy=True,
show_only_ip_addresses=True,
show_sub_policy=True,
show_template_policy=False,
show_upload_comment=True,
show_upload_history=True,
granted_template_policy=None,
granted_sub_policy=None,
granted_report_design=None,
filter_tag=None,
comment=None
):
"""
Create a web portal admin user account.
.. versionadded:: 0.6.2
Added can_use_api, console_superuser, and allowed_to_login_in_shared.
Requires SMC >= SMC 6.4
:param str name: name of account
:param bool enabled: is account enabled
:param list granted_engine: The list of Granted Engines
:param bool console_superuser: can this user sudo via SSH/console.
:param bool log_service_enabled: check if the log service enabled?
:param bool policy_service_enabled: check if the policy service enabled.
:param bool report_service_enabled: Is the report service enabled?
:param bool show_inspection_policy: Should we display the inspection policy?
:param bool show_main_policy: Should we display the main policy?
:param bool show_only_ip_addresses: Should we display only the IP Addresses of elements?
:param bool show_sub_policy: Should we display the sub policy?
:param bool show_template_policy: Should we display the template policy?
:param bool show_upload_comment: Should we display the upload comment?
:param bool show_upload_history: Should we display the upload history?
:param list granted_template_policy: The list of Granted Template Policies.
null value means ANY.
:param list granted_sub_policy: The list of Granted Sub Policies.
null value means ANY
:param list granted_report_design: The list of Granted Report Designs.
null value means ANY.
:param list filter_tag: The list of Filter expression tags for the log browsing.
null value means ANY.
:param str comment: comment,
:raises CreateElementFailed: failure creating element with reason
:return: instance with meta
:rtype: WebPortalAdminUser
"""
engines = [] if granted_engine is None else element_resolver(granted_engine)
policy = [] if granted_template_policy is None else element_resolver(
granted_template_policy)
sub_policy = [] if granted_sub_policy is None else element_resolver(granted_sub_policy)
report_design = [] if granted_report_design is None else element_resolver(
granted_report_design)
tag = [] if filter_tag is None else element_resolver(filter_tag)
json = {
"name": name,
"enabled": enabled,
"console_superuser": console_superuser,
"log_service_enabled": log_service_enabled,
"policy_service_enabled": policy_service_enabled,
"report_service_enabled": report_service_enabled,
"show_inspection_policy": show_inspection_policy,
"show_main_policy": show_main_policy,
"show_only_ip_addresses": show_only_ip_addresses,
"show_sub_policy": show_sub_policy,
"show_template_policy": show_template_policy,
"show_upload_comment": show_upload_comment,
"show_upload_history": show_upload_history,
"granted_engine": engines,
"granted_template_policy": policy,
"granted_sub_policy": sub_policy,
"granted_report_design": report_design,
"filter_tag": tag,
"comment": comment,
}
return ElementCreator(cls, json)
@property
def enabled(self):
return self.data.get("enabled")
@property
def granted_engine(self):
return self.data.get("granted_engine")
@property
def console_superuser(self):
return self.data.get("console_superuser")
@property
def log_service_enabled(self):
return self.data.get("log_service_enabled")
@property
def policy_service_enabled(self):
return self.data.get("policy_service_enabled")
@property
def report_service_enabled(self):
return self.data.get("report_service_enabled")
@property
def show_inspection_policy(self):
return self.data.data("show_inspection_policy")
@property
def show_main_policy(self):
return self.data.get("show_main_policy")
@property
def show_only_ip_addresses(self):
return self.data.get("show_only_ip_addresses")
@property
def show_sub_policy(self):
return self.data.get("show_sub_policy")
@property
def show_template_policy(self):
return self.data.get("show_template_policy")
@property
def show_upload_comment(self):
return self.data.get("show_upload_comment")
@property
def show_upload_history(self):
return self.data.get("show_upload_history")
@property
def granted_template_policy(self):
return self.data.get("granted_template_policy")
@property
def granted_sub_policy(self):
return self.data.get("granted_sub_policy")
@property
def granted_report_design(self):
return self.data.get("granted_report_design")
@property
def filter_tag(self):
return self.data.get("filter_tag")