blob: 2736a2038220a84b10a20f0245743f3ff8305fce [file] [log] [blame]
#!/usr/bin/env python
# -----------------------------------------------------------------------
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you 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.
# -----------------------------------------------------------------------
import sys
version_min = [2, 7]
version_info = sys.version_info
version_error = False
if(version_info[0] < version_min[0]):
version_error = True
elif(version_info[0] == version_min[0]):
if(version_info[1] < version_min[1]):
version_error = True
if(version_error):
print('Python minimum requirement is version '+str(version_min[0])+'.'+str(version_min[1]))
sys.exit(1)
import argparse
import datetime
import os
import time
import traceback
from ducc_util import DuccUtil
# print message
def output(msg):
print msg
# produce a time stamp
def get_timestamp():
tod = time.time()
timestamp = datetime.datetime.fromtimestamp(tod).strftime('%Y-%m-%d %H:%M:%S')
return timestamp
_flag_debug = False
# record debug message
def debug(mn,text):
if(_flag_debug):
type ='D'
msg = get_timestamp()+' '+type+' '+mn+' '+text
output(msg)
# command to check db access authorization
class AccessCheck(DuccUtil):
# return method name
def _mn(self):
return traceback.extract_stack(None,2)[0][2]
description = 'Determine if LOOKER can view OWNER database data through examination of db.access file in security directory, typically ~/.ducc.'\
+ ' Return 1 if authorized, 0 otherwise.'\
+ ' Rules: '\
+ ' 1. Authorized if OWNER == LOOKER'\
+ ' or '\
+ ' 2. Authorized if OWNER db.access file is readable by all'\
+ ' or '\
+ ' 3. Authorized if LOOKER groups contains the OWNER db.access file group'\
+ ''
def get_args(self):
global _flag_debug
parser = argparse.ArgumentParser(description=self.description)
parser.add_argument('--owner', '-o', action='store', required=True, help='the user who owns the data')
parser.add_argument('--looker', '-l', action='store', required=True, help='the user who views the data')
parser.add_argument('--debug', '-d', action='store_true', help='display debugging messages')
self.args = parser.parse_args()
_flag_debug = self.args.debug
# get property from ducc.properties file
def get_ducc_property(self, key):
value = self.ducc_properties.get(key)
text = 'key:'+key+' '+'value:'+value
debug(self._mn(),text)
# get DUCC security home directory, by default user's $HOME
def get_security_home(self):
key = 'ducc.security.home'
value = self.get_ducc_property(key)
if(value == None):
home_folder = os.getenv('HOME')
value = home_folder.rsplit('/',1)[0]
self.ducc_security_home = value
text = value
debug(self._mn(),text)
# Access: (0644/-rw-r--r--) Uid: ( 2077/watson) Gid: ( 2001/limited)
def get_permissions(self,line):
normalized_line = line
normalized_line = normalized_line.replace('(',' ')
normalized_line = normalized_line.replace(')',' ')
tokens = normalized_line.split()
permissions = tokens[1]
permissions = permissions.replace('/',' ')
permissions = permissions.strip()
permissions = permissions.split()[1]
# -rw-r--r--
return permissions
# Access: (0644/-rw-r--r--) Uid: ( 2077/watson) Gid: ( 2001/limited)
def get_group(self,line):
normalized_line = line
normalized_line = normalized_line.replace('(',' ')
normalized_line = normalized_line.replace(')',' ')
tokens = normalized_line.split()
group = tokens[5]
group = group.replace('/',' ')
group = group.strip()
group = group.split()[1]
# limited
return group
# get db.access file info, comprising file permissions and file group
def get_owner_access_data(self):
permissions = '----------'
group = ''
ducc_ling = self.duccling
self.get_security_home()
security_file = os.path.join(self.ducc_security_home,self.args.owner,'.ducc','db.access')
text = 'security_file:'+security_file
debug(self._mn(),text)
p0 = '-q'
p1 = '-u'
p2 = self.args.owner
p3 = '/usr/bin/stat'
p4 = security_file
cmd = ducc_ling+' '+p0+' '+p1+' '+p2+' '+p3+' '+p4
text = cmd
debug(self._mn(),text)
lines = self.popen(ducc_ling,p0,p1,p2,p3,p4)
for line in lines:
line = line.strip()
if(('Access:' in line) and ('Gid:' in line)):
permissions = self.get_permissions(line)
group = self.get_group(line)
text = 'permissions:'+permissions+' '+'group:'+group
debug(self._mn(),text)
break;
return permissions, group
# get looker's groups
def get_looker_groups(self):
groups = []
ducc_ling = self.duccling
p0 = '-q'
p1 = '-u'
p2 = self.args.owner
p3 = '/usr/bin/groups'
cmd = ducc_ling+' '+p0+' '+p1+' '+p2+' '+p3
text = cmd
debug(self._mn(),text)
lines = self.popen(ducc_ling,p0,p1,p2,p3)
for line in lines:
line = line.strip()
tokens = line.split()
groups = tokens
return groups
# check if looker is authorized to access owner's db info
def check_authorization(self):
authorized = 0
text = 'owner:'+self.args.owner+' '+'looker:'+self.args.looker
debug(self._mn(),text)
if(self.args.owner == self.args.looker):
authorized = 1
text = 'authorized:'+str(authorized)+' '+'reason: owner == looker'
debug(self._mn(),text)
else:
file_permissions, file_group = self.get_owner_access_data()
text = 'permissions:'+file_permissions+' '+'group:'+file_group
debug(self._mn(),text)
if(file_permissions[7] == 'r'):
authorized = 1
text = 'authorized:'+str(authorized)+' '+'reason: owner db.access file readable by all'
debug(self._mn(),text)
elif(file_permissions[4] == 'r'):
looker_groups = self.get_looker_groups()
text = 'groups:'+str(looker_groups)
debug(self._mn(),text)
if(file_group in looker_groups):
authorized = 1
text = 'authorized:'+str(authorized)+' '+'reason: looker in group assigned to db.access file'
debug(self._mn(),text)
return authorized
def main(self, argv):
authorized = 0
self.get_args()
authorized = self.check_authorization()
print str(authorized)
sys.exit(authorized)
if __name__ == '__main__':
instance = AccessCheck()
instance.main(sys.argv[1:])