diff --git a/app/cmd/user_create.go b/app/cmd/user_create.go new file mode 100644 index 0000000000000000000000000000000000000000..1f435fddf7e55602180b89f2ccee9bdaa2e32ac7 --- /dev/null +++ b/app/cmd/user_create.go @@ -0,0 +1,46 @@ +package cmd + +import ( + "fmt" + "log" + + "github.com/linuxsuren/jenkins-cli/client" + "github.com/spf13/cobra" +) + +type UserCreateOption struct { +} + +var userCreateOption UserCreateOption + +func init() { + userCmd.AddCommand(userCreateCmd) +} + +var userCreateCmd = &cobra.Command{ + Use: "create", + Short: "Create a user for your Jenkins", + Long: `Create a user for your Jenkins`, + Run: func(cmd *cobra.Command, args []string) { + if len(args) == 0 { + cmd.Help() + return + } + + username := args[0] + + jenkins := getCurrentJenkins() + jclient := &client.UserClient{} + jclient.URL = jenkins.URL + jclient.UserName = jenkins.UserName + jclient.Token = jenkins.Token + jclient.Proxy = jenkins.Proxy + jclient.ProxyAuth = jenkins.ProxyAuth + + if user, err := jclient.Create(username); err == nil { + fmt.Printf("create user success. Password is: %s\n", user.Password1) + } else { + log.Fatal(err) + } + }, +} diff --git a/app/cmd/user_delete.go b/app/cmd/user_delete.go new file mode 100644 index 0000000000000000000000000000000000000000..fac45e1bee7cfda39ef6468d10d4baa66db03171 --- /dev/null +++ b/app/cmd/user_delete.go @@ -0,0 +1,52 @@ +package cmd + +import ( + "fmt" + "log" + + "github.com/linuxsuren/jenkins-cli/client" + "github.com/spf13/cobra" +) + +type UserDeleteOption struct { + BatchOption +} + +var userDeleteOption UserDeleteOption + +func init() { + userCmd.AddCommand(userDeleteCmd) + userDeleteCmd.Flags().BoolVarP(&userDeleteOption.Batch, "batch", "b", false, "Batch mode, no need confirm") +} + +var userDeleteCmd = &cobra.Command{ + Use: "delete", + Short: "Delete a user for your Jenkins", + Long: `Delete a user for your Jenkins`, + Run: func(cmd *cobra.Command, args []string) { + if len(args) == 0 { + cmd.Help() + return + } + + username := args[0] + + if !userDeleteOption.Confirm(fmt.Sprintf("Are you sure to delete user %s ?", username)) { + return + } + + jenkins := getCurrentJenkins() + jclient := &client.UserClient{} + jclient.URL = jenkins.URL + jclient.UserName = jenkins.UserName + jclient.Token = jenkins.Token + jclient.Proxy = jenkins.Proxy + jclient.ProxyAuth = jenkins.ProxyAuth + + if err := jclient.Delete(username); err == nil { + fmt.Printf("delete user success.\n") + } else { + log.Fatal(err) + } + }, +} diff --git a/app/cmd/user_token.go b/app/cmd/user_token.go index d849ce569dba7338c1a94d6758a684db05d6086d..79681b479403dcd24965d3b59ede949db64bc217 100644 --- a/app/cmd/user_token.go +++ b/app/cmd/user_token.go @@ -40,7 +40,7 @@ var userTokenCmd = &cobra.Command{ jclient.ProxyAuth = jenkins.ProxyAuth tokenName := userTokenOption.Name - if status, err := jclient.Create(tokenName); err == nil { + if status, err := jclient.CreateToken(tokenName); err == nil { var data []byte if data, err = userOption.Output(status); err == nil { fmt.Printf("%s\n", string(data)) diff --git a/client/user.go b/client/user.go index 3b2f3cae477b8ce2350e000039107bfcd6bf7211..fe589179b8018a6140d67b984592e6c7bde8a92f 100644 --- a/client/user.go +++ b/client/user.go @@ -10,6 +10,7 @@ import ( "strings" "github.com/Pallinder/go-randomdata" + "github.com/linuxsuren/jenkins-cli/util" ) type UserClient struct { @@ -98,7 +99,86 @@ func (q *UserClient) EditDesc(description string) (err error) { return } -func (q *UserClient) Create(newTokenName string) (status *Token, err error) { +func (q *UserClient) Delete(username string) (err error) { + api := fmt.Sprintf("%s/securityRealm/user/%s/doDelete", q.URL, username) + var ( + req *http.Request + response *http.Response + ) + + req, err = http.NewRequest("POST", api, nil) + if err == nil { + q.AuthHandle(req) + } else { + return + } + + req.Header.Set("Content-Type", "application/x-www-form-urlencoded") + client := q.GetClient() + if response, err = client.Do(req); err == nil { + code := response.StatusCode + var data []byte + data, err = ioutil.ReadAll(response.Body) + if code != 200 && code != 302 { + log.Fatal(string(data)) + } + } else { + log.Fatal(err) + } + return +} + +func (q *UserClient) Create(username string) (user *UserForCreate, err error) { + api := fmt.Sprintf("%s/securityRealm/createAccountByAdmin", q.URL) + var ( + req *http.Request + response *http.Response + ) + + passwd := util.GeneratePassword(8) + + user = &UserForCreate{ + User: User{FullName: username}, + Username: username, + Password1: passwd, + Password2: passwd, + Email: fmt.Sprintf("%s@%s.com", username, username), + } + + userData, _ := json.Marshal(user) + formData := url.Values{ + "json": {string(userData)}, + "username": {username}, + "password1": {passwd}, + "password2": {passwd}, + "fullname": {username}, + "email": {user.Email}, + } + payload := strings.NewReader(formData.Encode()) + + req, err = http.NewRequest("POST", api, payload) + if err == nil { + q.AuthHandle(req) + } else { + return + } + + req.Header.Set("Content-Type", "application/x-www-form-urlencoded") + client := q.GetClient() + if response, err = client.Do(req); err == nil { + code := response.StatusCode + var data []byte + data, err = ioutil.ReadAll(response.Body) + if code != 200 && code != 302 { + log.Fatal(string(data)) + } + } else { + log.Fatal(err) + } + return +} + +func (q *UserClient) CreateToken(newTokenName string) (status *Token, err error) { if newTokenName == "" { newTokenName = fmt.Sprintf("jcli-%s", randomdata.SillyName()) } @@ -145,8 +225,16 @@ func (q *UserClient) Create(newTokenName string) (status *Token, err error) { } type User struct { - AbsoluteUrl string + AbsoluteURL string `json:"absoluteUrl"` Description string - FullName string + FullName string `json:"fullname"` ID string } + +type UserForCreate struct { + User `json:inline` + Username string `json:"username"` + Password1 string `json:"password1"` + Password2 string `json:"password2"` + Email string `json:"email"` +} diff --git a/util/password.go b/util/password.go new file mode 100644 index 0000000000000000000000000000000000000000..6d77316eea2a7c8b69830de7dbebab8c6ffd38a7 --- /dev/null +++ b/util/password.go @@ -0,0 +1,25 @@ +package util + +import ( + "math/rand" + "time" +) + +func GeneratePassword(length int) string { + rand.Seed(time.Now().UnixNano()) + digits := "0123456789" + specials := "~=+%^*/()[]{}/!@#$?|" + all := "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + + "abcdefghijklmnopqrstuvwxyz" + + digits + specials + buf := make([]byte, length) + buf[0] = digits[rand.Intn(len(digits))] + buf[1] = specials[rand.Intn(len(specials))] + for i := 2; i < length; i++ { + buf[i] = all[rand.Intn(len(all))] + } + rand.Shuffle(len(buf), func(i, j int) { + buf[i], buf[j] = buf[j], buf[i] + }) + return string(buf) +}