fix(vdu): vdu number of instances now is taking into account. Bug 1477
[osm/NBI.git] / osm_nbi / authconn_tacacs.py
1 # -*- coding: utf-8 -*-
2
3 # Copyright 2020 TATA ELXSI
4 #
5 # Licensed under the Apache License, Version 2.0 (the "License"); you may
6 # not use this file except in compliance with the License. You may obtain
7 # a copy of the License at
8 #
9 # http://www.apache.org/licenses/LICENSE-2.0
10 #
11 # Unless required by applicable law or agreed to in writing, software
12 # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13 # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14 # License for the specific language governing permissions and limitations
15 # under the License.
16 #
17 # For those usages not covered by the Apache License, Version 2.0 please
18 # contact: saikiran.k@tataelxsi.co.in
19 ##
20
21
22 """
23 AuthconnTacacs implements implements the connector for TACACS.
24 Leverages AuthconnInternal for token lifecycle management and the RBAC model.
25
26 When NBI bootstraps, it tries to create admin user with admin role associated to admin project.
27 Hence, the TACACS server should contain admin user.
28 """
29
30 __author__ = "K Sai Kiran <saikiran.k@tataelxsi.co.in>"
31 __date__ = "$11-Nov-2020 11:04:00$"
32
33
34 from osm_nbi.authconn import Authconn, AuthException
35 from osm_nbi.authconn_internal import AuthconnInternal
36 from osm_nbi.base_topic import BaseTopic
37
38 import logging
39 from time import time
40 from http import HTTPStatus
41
42 # TACACS+ Library
43 from tacacs_plus.client import TACACSClient
44
45
46 class AuthconnTacacs(AuthconnInternal):
47 token_time_window = 2
48 token_delay = 1
49
50 tacacs_def_port = 49
51 tacacs_def_timeout = 10
52 users_collection = "users_tacacs"
53 roles_collection = "roles_tacacs"
54 projects_collection = "projects_tacacs"
55 tokens_collection = "tokens_tacacs"
56
57 def __init__(self, config, db, role_permissions):
58 """
59 Constructor to initialize db and TACACS server attributes to members.
60 """
61 Authconn.__init__(self, config, db, role_permissions)
62 self.logger = logging.getLogger("nbi.authenticator.tacacs")
63 self.db = db
64 self.tacacs_host = config["tacacs_host"]
65 self.tacacs_secret = config["tacacs_secret"]
66 self.tacacs_port = config["tacacs_port"] if config.get("tacacs_port") else self.tacacs_def_port
67 self.tacacs_timeout = config["tacacs_timeout"] if config.get("tacacs_timeout") else self.tacacs_def_timeout
68 self.tacacs_cli = TACACSClient(self.tacacs_host, self.tacacs_port, self.tacacs_secret,
69 self.tacacs_timeout)
70
71 def validate_user(self, user, password):
72 """
73 """
74 now = time()
75 try:
76 tacacs_authen = self.tacacs_cli.authenticate(user, password)
77 except Exception as e:
78 raise AuthException("TACACS server error: {}".format(e), http_code=HTTPStatus.UNAUTHORIZED)
79 user_content = None
80 user_rows = self.db.get_list(self.users_collection, {BaseTopic.id_field("users", user): user})
81 if not tacacs_authen.valid:
82 if user_rows:
83 # To remove TACACS stale user from system.
84 self.delete_user(user_rows[0][BaseTopic.id_field("users", user)])
85 return user_content
86 if user_rows:
87 user_content = user_rows[0]
88 else:
89 new_user = {'username': user,
90 'password': password,
91 '_admin': {
92 'created': now,
93 'modified': now
94 },
95 'project_role_mappings': []
96 }
97 user_content = self.create_user(new_user)
98 return user_content
99
100 def create_user(self, user_info):
101 """
102 Validates user credentials in TACACS and add user.
103
104 :param user_info: Full user information in dict.
105 :return: returns username and id if credentails are valid. Otherwise, raise exception
106 """
107 BaseTopic.format_on_new(user_info, make_public=False)
108 try:
109 authen = self.tacacs_cli.authenticate(user_info["username"], user_info["password"])
110 if authen.valid:
111 user_info.pop("password")
112 self.db.create(self.users_collection, user_info)
113 else:
114 raise AuthException("TACACS server error: Invalid credentials", http_code=HTTPStatus.FORBIDDEN)
115 except Exception as e:
116 raise AuthException("TACACS server error: {}".format(e), http_code=HTTPStatus.BAD_REQUEST)
117 return {"username": user_info["username"], "_id": user_info["_id"]}
118
119 def update_user(self, user_info):
120 """
121 Updates user information, in particular for add/remove of project and role mappings.
122 Does not allow change of username or password.
123
124 :param user_info: Full user information in dict.
125 :return: returns None for successful add/remove of project and role map.
126 """
127 if(user_info.get("username")):
128 raise AuthException("Can not update username of this user", http_code=HTTPStatus.FORBIDDEN)
129 if(user_info.get("password")):
130 raise AuthException("Can not update password of this user", http_code=HTTPStatus.FORBIDDEN)
131 super(AuthconnTacacs, self).update_user(user_info)