diff --git a/README.md b/README.md index e72dafc..0c34e28 100644 --- a/README.md +++ b/README.md @@ -42,6 +42,7 @@ Tugboat is designed to make modifications to specific computer records on your J | Date | Notes | | ---------- | ---------------------------------------- | +| 2018.01.29 | Updated Tugboat 1.7.1 | | 2018.01.25 | Updated Tugboat 1.7 | | 2018.01.15 | Updated Tugboat 1.5.4 and Cargo Ship 1.0.4 | | 2018.01.03 | Updated Tugboat 1.5.3 and Cargo Ship 1.0.3 | diff --git a/tugboat/README.md b/tugboat/README.md index 18d84cf..08d0295 100644 --- a/tugboat/README.md +++ b/tugboat/README.md @@ -18,7 +18,9 @@ This version is highly modified from our internal version. Please see the follow 1/15/18: Released version 1.5.4 of Tugboat. Host preference file and light code cleanup. -**1/25/18: Released version 1.7 of Tugboat. Added logic to handle users with full editing privileges and read-only users. Additional logging added to support user levels and diagnose privilege issues. Included Windows executable again. The login functions in Tugboat and Cargo Ship are diverging, since Cargo Ship was always read-only by nature.** +1/25/18: Released version 1.7 of Tugboat. Added logic to handle users with full editing privileges and read-only users. Additional logging added to support user levels and diagnose privilege issues. Included Windows executable again. The login functions in Tugboat and Cargo Ship are diverging, since Cargo Ship was always read-only by nature. + +**1/29/18: Released version 1.7.1 of Tugboat. In audit (read-only) mode, the UI now correctly indicates that the information from the database cannot be changed. Corrected a login bug.** ## Contents @@ -208,9 +210,9 @@ The most obvious area for customization is utilizing an external source of infor ### ldap_object.py -This is Python object that consumes an LDAP record for a user and makes the data available to the developer by asking specific questions of it. "Is this person a student?", "What is this persons email address?", etc. Integrating this object with your code will require familiarity with the schema used by your particular institution. +This is a python object that consumes an LDAP record from [dscl](https://developer.apple.com/legacy/library/documentation/Darwin/Reference/ManPages/man1/dscl.1.html) for a user and makes the data available to the developer by asking specific questions of it. "Is this person a student?", "What is this persons email address?", etc. Integrating this object with your code will require familiarity with the schema used by your particular institution. -The object as written requires underlying MacOS tools and does not rely on any additional Python modules. However, it may be helpful guiding you if you prefer to use another module for interacting with your particular LDAP. +The object as written requires underlying MacOS tools and does not rely on any additional Python modules. However, it may be helpful guiding you if you prefer to use another module for interacting with your particular LDAP or directory server. ### database_funtion.py @@ -234,6 +236,7 @@ My heartfelt thanks to the other members of the Mac Group and the IT administrat | Date | Version | Notes | | ---------- | ------- | ---------------------------------------- | +| 2018.01.29 | 1.7.1 | Adjusted UI to reflect read-only nature of audit mode. Login bug corrected. | | 2018.01.25 | 1.7.0 | Added full/read-only user support. Additional logging. | | 2018.01.15 | 1.5.4 | Host preference file. Light code cleanup. | | 2018.01.03 | 1.5.3 | Improved LDAP logins. | diff --git a/tugboat/Tugboat application macOS.dmg b/tugboat/Tugboat application macOS.dmg index 9036eca..7c5e241 100644 Binary files a/tugboat/Tugboat application macOS.dmg and b/tugboat/Tugboat application macOS.dmg differ diff --git a/tugboat/imgs/internal_tugboat.png b/tugboat/imgs/internal_tugboat.png index 7ed17ed..f7b0c32 100644 Binary files a/tugboat/imgs/internal_tugboat.png and b/tugboat/imgs/internal_tugboat.png differ diff --git a/tugboat/tugboat.py b/tugboat/tugboat.py index f149f4f..4154f17 100755 --- a/tugboat/tugboat.py +++ b/tugboat/tugboat.py @@ -33,9 +33,11 @@ # 1.5.4 2018.01.15 Host preference file. tjm # Light code cleanup # -# 1.6.0 2018.01.25 Full/Auditing user login support. tjm -# increased, fine-grained logging. +# 1.7.0 2018.01.25 Full/Auditing user login support. tjm +# Increased, fine-grained logging. # +# 1.7.1 2018.01.28 UI limited in audit mode. tjm +# Bug in login code corrected. # ################################################################################ @@ -54,8 +56,7 @@ # Unify all jss calls in single generic method, something like: # ('call_jss(logger, api_call)') # -# Set fields to disabled when auditing. -# +# Add correct windows logging. # # ################################################################################ @@ -80,6 +81,9 @@ import webbrowser import xml.etree.cElementTree as ET from Tkinter import * + +# +# Need to implement correct windows-appropriate logging. if platform.system() == 'Darwin': import pexpect import pwd @@ -88,7 +92,10 @@ except: import logging else: - import logging + try: + from management_tools import loggers + except: + import logging class Computer(object): @@ -104,6 +111,7 @@ def __init__(self, root, logger, jamf_hostname, jamf_username, jamf_password, ac self.jamf_hostname = jamf_hostname self.jamf_password = jamf_password self.jamf_username = jamf_username + self.access_level = access_level self.local_jamf_id = None self.hostname = "" @@ -372,7 +380,7 @@ def build_ui(self): BAMCAQAAOw== ''' - self.root.title("Tugboat 1.7") + self.root.title("Tugboat 1.7.1") self.mainframe = ttk.Frame(self.root) @@ -405,7 +413,10 @@ def build_ui(self): if platform.system() == 'Darwin': ttk.Label(self.mainframe, text="User Selection:").grid(column=1, row=150, sticky=E) - ttk.Button(self.mainframe, text="Top User (Admin Req.)", command=self.usage).grid(column=2, row=150, sticky=W) + if self.access_level == 'full': + ttk.Button(self.mainframe, text="Top User (Admin Req.)", command=self.usage).grid(column=2, row=150, sticky=W) + else: + ttk.Button(self.mainframe, text="Top User (Admin Req.)", command=self.usage, state='disabled').grid(column=2, row=150, sticky=W) # # If you are considering adding UI elements to communicate with user database, place them here @@ -496,6 +507,18 @@ def build_ui(self): self.submit_btn = ttk.Button(self.mainframe, text="Auditing", state='disabled') self.submit_btn.grid(column=4, row=1100, sticky=E) + self.computername_entry.configure(state='disabled') + self.assettag_entry.configure(state='disabled') + self.barcode_entry.configure(state='disabled') + self.endusername_entry.configure(state='disabled') + self.fullname_entry.configure(state='disabled') + self.division_combobox.configure(state="disabled") + self.position_entry.configure(state='disabled') + self.email_entry.configure(state='disabled') + self.phone_entry.configure(state='disabled') + self.building_combobox.configure(state="disabled") + self.room_entry.configure(state='disabled') + # # this loop adds a small amount of space around each UI element, changing the value will significantly change the final size of the window for child in self.mainframe.winfo_children(): @@ -1022,7 +1045,7 @@ def button_state(self): self.logger.info("%s: activated" % inspect.stack()[0][3]) - if self.platform == "Mac": + if self.platform == "Mac" and self.access_level == 'full': self.jamf_management_btn.configure(state="normal") else: @@ -1649,6 +1672,9 @@ def call_jss(logger, api_call): if error.code == 401: logger.error("%s: Invalid username or password. (%r) (%s)" % (inspect.stack()[0][3], jamf_username.get(), api_call)) tkMessageBox.showerror("Jamf login", "Invalid username or password.") + elif error.code == 404: + logger.warn("%s: JSS account not found. [%s]" % (inspect.stack()[0][3], jamf_username.get())) + return None else: logger.error("%s: Error communicating with JSS. %s %s" % (inspect.stack()[0][3], jamf_hostname.get(), api_call)) tkMessageBox.showerror("Jamf login", "HTTP error from:\n%s" % jamf_hostname.get()) @@ -1750,27 +1776,29 @@ def call_jss(logger, api_call): missing_update_privileges = [] try: raw_privileges = call_jss(logger, 'accounts/username/' + jamf_username.get()) - user_privileges = raw_privileges['account']['privileges']['jss_objects'] - for item in read_privileges: - if item not in user_privileges: - missing_read_privileges.append(item) + if raw_privileges: + user_privileges = raw_privileges['account']['privileges']['jss_objects'] + + for item in read_privileges: + if item not in user_privileges: + missing_read_privileges.append(item) - if not missing_read_privileges: - user_read = True + if not missing_read_privileges: + user_read = True - for item in update_privileges: - if item not in user_privileges: - missing_update_privileges.append(item) + for item in update_privileges: + if item not in user_privileges: + missing_update_privileges.append(item) - if not missing_update_privileges: - user_update = True + if not missing_update_privileges: + user_update = True - if missing_read_privileges or missing_update_privileges: - logger.warn("login: %s is missing privileges for full access: %r" % (jamf_username.get(), missing_read_privileges + missing_update_privileges)) + if missing_read_privileges or missing_update_privileges: + logger.warn("login: %s is missing privileges for full access: %r" % (jamf_username.get(), missing_read_privileges + missing_update_privileges)) except Exception as exception_message: - logger.info("%s: Error checking user account info. (%r)" % (inspect.stack()[0][3], exception_message)) + logger.warn("%s: Error checking user account info. (%r)" % (inspect.stack()[0][3], exception_message)) # # if all require privileges accounted for, proceed diff --git a/tugboat/tugboat_exe.zip b/tugboat/tugboat_exe.zip index d859046..2cf8ed9 100755 Binary files a/tugboat/tugboat_exe.zip and b/tugboat/tugboat_exe.zip differ