From cdc4c4e6a93645280906c0e31c93b3e515a207b7 Mon Sep 17 00:00:00 2001 From: Alec Clews Date: Mon, 18 May 2020 16:43:40 +1000 Subject: [PATCH] Moved Cust Auth/Sync Material to New repo --- Authentication/README.md | 1 + Authentication/cust-auth-sync.go | 350 ------------------------------- Authentication/customUser.py | 136 ------------ 3 files changed, 1 insertion(+), 486 deletions(-) create mode 100644 Authentication/README.md delete mode 100644 Authentication/cust-auth-sync.go delete mode 100755 Authentication/customUser.py diff --git a/Authentication/README.md b/Authentication/README.md new file mode 100644 index 0000000..66c7023 --- /dev/null +++ b/Authentication/README.md @@ -0,0 +1 @@ +# This material has moved to https://github.com/PaperCutSoftware/CustomSynAndAuthentication diff --git a/Authentication/cust-auth-sync.go b/Authentication/cust-auth-sync.go deleted file mode 100644 index 915c20d..0000000 --- a/Authentication/cust-auth-sync.go +++ /dev/null @@ -1,350 +0,0 @@ -// A PaperCut MG/NG user directory source -package main - -// Build -// go get github.com/divan/gorilla-xmlrpc/xml -// go build cust-auth-sync.go - -// Install: -// Copy the cust-auth-sync binary to [papercut install dir]/server/custom/local - -// Config -// In the PaperCut MF/NG admin interface select -// [options] -> [User/Group Sync]. Under [Primary Sync Source] set these values - -// [Primary sync source] => [Custom Program ....] -// [Custom user program] => [C:\Program Files\PaperCut MF\server\custom\local\cust-auth-sync.exe] -// [Custom auth program] => [C:\Program Files\PaperCut MF\server\custom\local\cust-auth-sync.exe] - -// Note modify the path and name of the binary depending on your platform - -// This is a demo program so it comes with a default sample database. The -// 1st time the program is run it will create a json file with the sample -// data. Edit this file at any time to change the user and group databases, -// and the web services API token. - -// Note after copying the binary -// into the [papercut install dir]/server/custom/local directory, but before -// performing the 1st user sync you can create the sample database and then -// edit the data. run the command -// [papercut install dir]/server/custom/local/cust-auth-sync - is-valid - -// This will create the database in [papercut install dir]/server/custom/local/config.json - -// Note: This program assumes the advanced config key user-source.update-user-details-card-id -// is set to "Y" - -import ( - "bytes" - "encoding/json" - "fmt" - "io/ioutil" - "log" - "net/http" - "os" - "path/filepath" - - "github.com/divan/gorilla-xmlrpc/xml" -) - -// Stuff to call the PaperCut web services API over XML-RPC - -type client struct { - uri string - port string - authToken string -} - -// Make the RPC call -func xmlRpcCall(c client, method string, args interface{}, reply interface{}) error { - buf, _ := xml.EncodeClientRequest(method, args) - response, err := http.Post(c.uri+":"+c.port+"/rpc/api/xmlrpc", "text/xml", bytes.NewBuffer(buf)) - if err != nil { - return err - } - defer response.Body.Close() // Can't defer until we know we have a response - err = xml.DecodeClientResponse(response.Body, reply) - return err -} - -func (c client) getConfigValue(keyName string) (string, error) { - var args interface{} - - args = &struct { - Auth string - KeyName string - }{ - c.authToken, - keyName, - } - - var reply struct{ ReturnValue string } - err := xmlRpcCall(c, "api.getConfigValue", args, &reply) - return reply.ReturnValue, err -} - -func getConfigValue(token string, configName string) string { - papercutServer := "http://localhost" - papercutPort := "9191" - - r, err := client{papercutServer, papercutPort, token}.getConfigValue(configName) - - if err == nil { - return r - } - - fmt.Fprintln(os.Stderr, "Cannot use web services API. Please configure", err) - return "" -} - -func areUserNameAliasesEnabled(token string) (ret bool) { - - r := getConfigValue(token, "secondary-user-name.enabled") - - if len(r) > 0 { - if r != "N" { - fmt.Fprintln(os.Stderr, "PaperCut MF/NG is configured for secondary usernames (aliases)") - return true - } else { - fmt.Fprintln(os.Stderr, "PaperCut MF/NG is NOT configured for secondary usernames (aliases)") - } - } - return false -} - -// End of web services helper - -type userDBT map[string]userAttributesT - -type userAttributesT struct { - Fullname string `json:"fullname"` - Email string `json:"email"` - Dept string `json:"dept"` - Office string `json:"office"` - PrimaryCardno string `json:"primarycardno"` - OtherEmail string `json:otheremail` - SecondaryCardno string `json:secondarycardno` - UserAlias string `json:useralias` - HomeDirectory string `json:homedirectory` - PIN string `json:pin` - Password string `json:"password"` -} - -type userDataT struct { - Username string `json:"username"` - userAttributesT -} - -func (db userDBT) saveUser(userData userDataT) (err error) { - if _, found := db.findUser(userData.Username); found { - return fmt.Errorf("Duplicate user. Can't insert %v", userData.Username) - } - db[userData.Username] = userData.userAttributesT - return nil -} - -func (db userDBT) findUser(userName string) (userData userDataT, userFound bool) { - for user, attributes := range db { - if userName == user { - return userDataT{ - Username: user, - userAttributesT: attributes}, true - } - } - return userDataT{}, false -} - -var userAliasConfigured bool - -func (user userDataT) String() string { - - userAlias := "" - - if userAliasConfigured { - userAlias = user.UserAlias - } - - return fmt.Sprintf("%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s", - user.Username, - user.Fullname, - user.Email, - user.Dept, - user.Office, - user.PrimaryCardno, - user.OtherEmail, - user.SecondaryCardno, - userAlias, - user.HomeDirectory, - user.PIN, - ) - // Don't return the user Password -- it's meant to be a secret! -} - -type configT struct { - WebServicesToken string `json:auth.webservices.auth-token` - UDB userDBT `json:"userdata"` - GDB map[string][]string `json:"groupdata"` -} - -// Create some sample data and save it to disk -func saveConfig(filename string) (string, userDBT, map[string][]string, error) { - - fmt.Fprintf(os.Stderr, "Creating new default user and group database in %v\n", filename) - userDB := make(userDBT) - groupDB := make(map[string][]string) - - userDB.saveUser(userDataT{Username: "john", userAttributesT: userAttributesT{Fullname: "John Smith", Email: "johns@here.com", Dept: "Accounts", Office: "Melbourne", PrimaryCardno: "1234", OtherEmail: "personal1@webmail.com", SecondaryCardno: "01234", UserAlias: "user1", HomeDirectory: "\\\\server\\dfs\\homedirs\\user1", PIN: "1234", Password: "password1"}}) - userDB.saveUser(userDataT{Username: "jane", userAttributesT: userAttributesT{Fullname: "Jane Rodgers", Email: "janer@here.com", Dept: "Sales", Office: "Docklands", PrimaryCardno: "5678", OtherEmail: "personal2@webmail.com", SecondaryCardno: "05678", UserAlias: "user2", HomeDirectory: "\\\\server\\dfs\\homedirs\\user2", PIN: "1234", Password: "password2"}}) - userDB.saveUser(userDataT{Username: "ahmed", userAttributesT: userAttributesT{Fullname: "Ahmed Yakubb", Email: "ahmedy@here.com", Dept: "Marketing", Office: "Home Office", PrimaryCardno: "4321", OtherEmail: "personal2@webmail.com", SecondaryCardno: "04321", UserAlias: "user3", HomeDirectory: "\\\\server\\dfs\\homedirs\\user3", PIN: "1234", Password: "password3"}}) - - groupDB["groupA"] = []string{"john"} - groupDB["groupB"] = []string{"jane", "ahmed"} - - token := "change-me" - - c := configT{token, userDB, groupDB} - - bytes, err := json.MarshalIndent(c, "", " ") - if err != nil { - return token, userDBT{}, map[string][]string{}, err - } - - return token, userDB, groupDB, ioutil.WriteFile(filename, bytes, 0644) -} - -// Read user and group database from disk -func getConfig() (token string, udb userDBT, gdb map[string][]string, err error) { - - dir, err := filepath.Abs(filepath.Dir(os.Args[0])) - if err != nil { - log.Fatal(err) - } - - filename := filepath.FromSlash(fmt.Sprintf("%v/%v", dir, "config.json")) - - bytes, err := ioutil.ReadFile(filename) - if err != nil { - fmt.Fprintf(os.Stderr, "Could not read config file %v\n", err) - token, udb, gdb, err := saveConfig(filename) - if err != nil { - fmt.Fprintln(os.Stderr, err) - } - return token, udb, gdb, err - } - - var c configT - err = json.Unmarshal(bytes, &c) - if err != nil { - return token, userDBT{}, map[string][]string{}, err - } - - return c.WebServicesToken, c.UDB, c.GDB, nil -} - -func main() { - - token, userDB, groupDB, err := getConfig() - - if err != nil { - fmt.Fprintln(os.Stderr, "config error") - os.Exit(-1) - } - - if len(os.Args) == 1 { - var userName, password string - - fmt.Scan(&userName, &password) - - user, userFound := userDB.findUser(userName) - - if userFound && user.Password == password { - fmt.Printf("OK\n%s\n", user.Username) - os.Exit(0) - } - - fmt.Fprintln(os.Stderr, "Wrong Username or Password") - fmt.Println("ERROR") - os.Exit(-1) - } - - if len(os.Args) == 2 || os.Args[1] != "-" { - fmt.Fprintf(os.Stderr, "Incorrect arguments passed: %v\n", os.Args[1:]) - os.Exit(-1) - } - - userAliasConfigured = areUserNameAliasesEnabled(token) - - if os.Args[2] == "is-valid" { - fmt.Println("Y") - os.Exit(0) - } - - if os.Args[2] == "all-users" { - for user := range userDB { - userdata, _ := userDB.findUser(user) - fmt.Println(userdata) - } - os.Exit(0) - } - - if os.Args[2] == "all-groups" { - for g := range groupDB { - fmt.Println(g) - } - os.Exit(0) - } - - if os.Args[2] == "get-user-details" { - var userName string - fmt.Scan(&userName) - if user, userFound := userDB.findUser(userName); userFound { - fmt.Println(user) - os.Exit(0) - } - fmt.Fprintf(os.Stderr, "Can't find user %s", userName) - os.Exit(-1) - } - - if os.Args[2] == "group-member-names" || - os.Args[2] == "group-members" || - os.Args[2] == "is-user-in-group" { - - if len(os.Args) < 4 { - fmt.Fprintln(os.Stderr, "group info request -- no group name supplied") - os.Exit(-1) - } - - if os.Args[2] == "is-user-in-group" && len(os.Args) < 5 { - fmt.Fprintln(os.Stderr, "is-user-in-group -- no user name supplied") - os.Exit(-1) - } - - for g, members := range groupDB { - if g == os.Args[3] { - for _, member := range members { - if os.Args[2] == "group-members" { - u, _ := userDB.findUser(member) - fmt.Println(u) - } else if os.Args[2] == "group-member-names" { - fmt.Println(member) - } else { //"is-user-in-group" - if member == os.Args[4] { - fmt.Println("Y") - os.Exit(0) - } - } - } - if os.Args[2] == "is-user-in-group" { - fmt.Println("N") - os.Exit(-1) - } - os.Exit(0) - } - } - fmt.Fprintln(os.Stderr, "Group not found") - os.Exit(-1) - } - - fmt.Fprintln(os.Stderr, "Can't process arguments", os.Args[1:]) - os.Exit(-1) -} diff --git a/Authentication/customUser.py b/Authentication/customUser.py deleted file mode 100755 index 1167714..0000000 --- a/Authentication/customUser.py +++ /dev/null @@ -1,136 +0,0 @@ -#!/usr/bin/env python3 - - -# A trivial example of a custom user program for use with PaperCut NG or MF -# See http://www.papercut.com/kb/Main/CaseStudyCustomUserSyncIntegration -# -# Uses Python 3 for dictionaries and be X platform. Make sure that the -# Python interpreter is on the path for the PaperCut service account or specify -# the path explicitly. - -# N.B. This example is for illustrative purposes only. Any production solution -# needs to be optimised for performance. - -import sys -import logging -import xmlrpc.client -from ssl import create_default_context, Purpose - -auth="token" -host="https://localhost:9192/rpc/api/xmlrpc" - -userDatabase = { - "john": {"fullname":"John Smith", "email":"johns@here.com", "dept":"Accounts", "office":"Melbourne", "cardno":"1234", "otherEmails":"personal1@webmail.com", "secondarycardno":"01234","password":"password1"}, - "jane": {"fullname":"Jane Rodgers", "email":"janer@here.com", "dept":"Sales", "office":"Docklands", "cardno":"5678", "otherEmails":"personal2@webmail.com", "secondarycardno":"05678", "password":"password2"}, - "ahmed":{"fullname":"Ahmed Yakubb", "email":"ahmedy@here.com", "dept":"Marketing", "office":"Home Office", "cardno":"4321", "otherEmails":"personal3@webmail.com", "secondarycardno":"04321", "password":"password3"}, -} - -groupDatabase = { - "groupA":["john"], - "groupB":["ahmed", "jane"], -} - -# logging.basicConfig(level=logging.DEBUG, filename="/tmp/logfile", filemode="a+", -# format="%(asctime)-15s %(levelname)-8s %(message)s") - -# logging.info("Called with {}".format(sys.argv)) - - -def formatUserDetails(userName): - if userName in userDatabase: - if extraData: - return '\t'.join([userName, userDatabase[userName]["fullname"], userDatabase[userName]["email"], userDatabase[userName]["dept"], userDatabase[userName]["office"], - userDatabase[userName]["cardno"], userDatabase[userName]["otherEmails"], userDatabase[userName]["secondarycardno"]]) - else: - return '\t'.join([userName, userDatabase[userName]["fullname"], userDatabase[userName]["email"], userDatabase[userName]["dept"], userDatabase[userName]["office"]]) - else: - print("Call to formatUserDetails error for username {}".format(userName), file=sys.stderr) - sys.exit(-1) - -# Should be return short or long form user data? Let's ask PaperCut MF/NG -proxy = xmlrpc.client.ServerProxy(host, verbose=False, - context = create_default_context(Purpose.CLIENT_AUTH)) - -try: - extraData = "N" != proxy.api.getConfigValue(auth, "user-source.update-user-details-card-id") -except Exception: - print("Cannot use web services API. Please configure", file=sys.stderr) - sys.exit(-1) - -# Being called as user auth program -if len(sys.argv) == 1: - name = input() - password = input() - if name in userDatabase and userDatabase[name]["password"] == password: - print("OK\n{}\n".format(name)) # Note: return canonical user name - sys.exit(0) - else: - print("Wrong username or password", file=sys.stderr) - print("ERROR\n") - sys.exit(-1) - -if len(sys.argv) < 2 or sys.argv[1] != '-': - print("incorrect argument passed {0}".format(sys.argv), file=sys.stderr) - sys.exit(-1) - -# Being called as user sync program -if sys.argv[2] == "is-valid": - print('Y') - print("long form user data record will provided" if extraData else "short form user data record will provided") - sys.exit(0) - -if sys.argv[2] == "all-users": - for name in userDatabase: - print(formatUserDetails(name)) - sys.exit(0) - -if sys.argv[2] == "all-groups": - print('\n'.join([g for g in groupDatabase])) - sys.exit(0) - -if sys.argv[2] == "get-user-details": - name = input() - if name in userDatabase: - print(formatUserDetails(name)) - sys.exit(0) - else: - print("Can't find user {0}".format(name), file=sys.stderr) - sys.exit(-1) - -if sys.argv[2] == "group-member-names": - if sys.argv[3] in groupDatabase: - for user in groupDatabase[sys.argv[3]]: - if user in userDatabase: - print(user) - else: - print("Invalid user name {} found in group list {}".format(user, group), file=sys.stderr) - sys.exit(-1) - sys.exit(0) - else: - print("Group name {} not found".format(sys.argv[3]), file=sys.stderr) - sys.exit(-1) - -if sys.argv[2] == "group-members": - if sys.argv[3] in groupDatabase: - for user in groupDatabase[sys.argv[3]]: - if user in userDatabase: - print(formatUserDetails(user)) - else: - print("Invalid user name {} found in group list {}".format(user, group), file=sys.stderr) - sys.exit(-1) - sys.exit(0) - else: - print("Group name {} not found".format(sys.argv[3]), file=sys.stderr) - sys.exit(-1) - -if sys.argv[2] == "is-user-in-group": - if sys.argv[3] in groupDatabase: - if sys.argv[4] in groupDatabase[sys.argv[3]]: - print('Y') - sys.exit(0) - print('N') - sys.exit(0) - print("Invalid Group name {}".format(sys.argv[3]), file=sys.stderr) - sys.exit(-1) - -print("Can't process arguments {0}".format(sys.argv), file=sys.stderr)