func pubkeyAuthCallback(conn ssh.ConnMetadata, key ssh.PublicKey) (*ssh.Permissions, error) { keyring.RLock() defer keyring.RUnlock() if keyring.Keys == nil { log.Println("rejecting authentication due to missing keyring") return nil, errors.New("no keyring available") } var keyFound *BenutzerDBKeyHandle for _, k := range *keyring.Keys { if k.ParsedPublicKey == nil { continue } else if bytes.Compare(key.Marshal(), k.ParsedPublicKey.Marshal()) == 0 { keyFound = &k break } } if keyFound == nil { log.Println("could not authenticate", conn.RemoteAddr().String(), " no key found") return nil, errors.New("invalid authentication") } log.Println("accepted key for user:"******"user_id": keyFound.Handle}}, nil }
func keyAuth(conn ssh.ConnMetadata, key ssh.PublicKey) (*ssh.Permissions, error) { log.Printf("(keyAuth) >> New client conn from '%s' authenticating with '%s'\n", conn.RemoteAddr(), key.Type()) // Check if the user is allowed to connect at all (meaning: the must be a subdirectory in the 'data' dir // matching the provided SSH username). authorizedPubKey, err := getPubKeyForUser(conn.User()) if err != nil { return nil, fmt.Errorf("(keyAuth) >> No pub key for user '%s' found / user not allowed to connect.", conn.User()) } fpProvidedPubKey, err := pubKeyFingerprint(key) if err != nil { log.Printf("(keyAuth) >> Error: Unable to create fingerprint for provided PubKey: %s\n", err.Error()) } log.Printf("(keyAuth) >> Fingerprint of provided PubKey : %s\n", fpProvidedPubKey) fpAuthorizedPubKey, err := pubKeyFingerprint(authorizedPubKey) if err != nil { log.Printf("(keyAuth) >> Error: Unable to create fingerprint for authorized PubKey: %s\n", err.Error()) } log.Printf("(keyAuth) >> Fingerprint of authorized PubKey: %s\n", fpAuthorizedPubKey) // Check if username and Public Key combination is allowed to establish a connection. if theseTwoPublicKeysAreEqual(key, authorizedPubKey) { log.Printf("(keyAuth) >> Correct username '%s' and public key provided.", conn.User()) // Signaling success / authentication passed. return nil, nil } log.Printf("(keyAuth) >> Wrong username '%s' and/or public key provided.", conn.User()) return nil, fmt.Errorf("Wrong username and/or public key.") }
func closeConn(conn ssh.ConnMetadata) error { Lock.Lock() defer Lock.Unlock() defer delete(MetaData, conn.RemoteAddr()) logs.Debug("Clean sessions") return nil }
func getClient(conn ssh.ConnMetadata) (*ssh.Client, error) { Lock.RLock() defer Lock.RUnlock() meta := MetaData[conn.RemoteAddr()] logs.Debug("Connection accepted from", conn.RemoteAddr()) return meta.Client, nil }
func parseIpPortFrom(conn ssh.ConnMetadata) (string, int) { remote := strings.Split(conn.RemoteAddr().String(), ":") port, err := strconv.Atoi(remote[1]) if err != nil { port = 0 } return remote[0], port }
func baseAlertMap(metadata ssh.ConnMetadata) map[string]string { meta := make(map[string]string) meta["service"] = "ssh" meta["user"] = metadata.User() meta["remote"] = metadata.RemoteAddr().String() meta["local"] = metadata.LocalAddr().String() return meta }
/* ci returns a string containing info from an ssh.ConnMetadata */ func ci(m ssh.ConnMetadata) string { return fmt.Sprintf( "Address:%v Target:%v Version:%q User:%q", m.RemoteAddr(), victimName(m), m.ClientVersion(), m.User(), ) }
// authPassword records any incoming request trying to auth with a username/password func authPassword(conn ssh.ConnMetadata, password []byte) (*ssh.Permissions, error) { log.Printf("sshPass: %s %s %s\n", conn.RemoteAddr().String(), conn.User(), strconv.QuoteToASCII(string(password))) return nil, errAuthenticationFailed }
/* logAttempt logs an authorization attempt. */ func logAttempt(conn ssh.ConnMetadata, method, cred string, suc bool) { log.Printf( "Address:%v Authorization Attempt Version:%q User:%q %v:%q "+ "Successful:%v", conn.RemoteAddr(), string(conn.ClientVersion()), conn.User(), method, cred, suc, ) }
// authKey records any incoming request trying to auth with an ssh key func authKey(conn ssh.ConnMetadata, key ssh.PublicKey) (*ssh.Permissions, error) { h := sha256.New() h.Write(key.Marshal()) sum := h.Sum(nil) log.Printf("sshkey: %s %s %s %s\n", conn.RemoteAddr().String(), conn.User(), key.Type(), base64.StdEncoding.EncodeToString(sum)) return nil, errAuthenticationFailed }
func (s ScriptPassAuth) Auth(conn ssh.ConnMetadata, password []byte) (*ssh.Permissions, error) { cmd := exec.Command(config.PassAuthLocation, conn.User(), conn.RemoteAddr().String()) passReader := bytes.NewReader(password) cmd.Stdin = passReader output, err := cmd.CombinedOutput() if err != nil { config.Log.Error("password authentication: %s\n%v", output, err) return nil, err } // nil permissions is success? return nil, nil }
func (sshClient *sshClient) authLogCallback(conn ssh.ConnMetadata, method string, err error) { if err != nil { if sshClient.sshServer.config.UseFail2Ban() { clientIPAddress := psiphon.IPAddressFromAddr(conn.RemoteAddr()) if clientIPAddress != "" { LogFail2Ban(clientIPAddress) } } log.WithContextFields(LogFields{"error": err, "method": method}).Warning("authentication failed") } else { log.WithContextFields(LogFields{"error": err, "method": method}).Info("authentication success") } }
func (s ScriptKeyAuth) Auth(conn ssh.ConnMetadata, key ssh.PublicKey) (*ssh.Permissions, error) { cmd := exec.Command(config.KeyAuthLocation, conn.User(), conn.RemoteAddr().String()) k := fmt.Sprintf("%s\n", base64.StdEncoding.EncodeToString(key.Marshal())) keyReader := bytes.NewReader([]byte(k)) cmd.Stdin = keyReader output, err := cmd.CombinedOutput() if err != nil { config.Log.Error("key authentication: %s\n%v", output, err) return nil, err } // nil permissions is success? return nil, nil }
// SCP Password authentication check func (a authDB) AuthSCPPassword(cmd ssh.ConnMetadata, pass []byte) (*ssh.Permissions, error) { // Get the client c := a.findClient(cmd.RemoteAddr().String()) if c == nil { return nil, fmt.Errorf("Unknown host %s", cmd.RemoteAddr().String()) } // Check Password if string(pass) == c.Protocols.SCP.Password { return nil, nil } return nil, fmt.Errorf("Authencation failed") }
// authPassword records any incoming request trying to auth with a username/password func authPassword(conn ssh.ConnMetadata, password []byte) (*ssh.Permissions, error) { r := &AuthEvent{ Time: fmt.Sprintf("%d", time.Now().Unix()), AuthType: "sshPass", SrcIP: strings.Split(conn.RemoteAddr().String(), ":")[0], DestIP: extIP, User: conn.User(), TypeData: fmt.Sprintf("client-version: %s", strconv.QuoteToASCII(string(conn.ClientVersion()))), Credentials: strconv.QuoteToASCII(string(password)), } addToBatch(r) return nil, errAuthenticationFailed }
func keyAuth(conn ssh.ConnMetadata, key ssh.PublicKey) (*ssh.Permissions, error) { log.Println(conn.RemoteAddr(), "authenticate with", key.Type(), "for user", conn.User()) log.Println(base64.StdEncoding.EncodeToString(key.Marshal())) if isValidToken(conn.User()) { authRequestMap.Lock() authRequestMap.matches[conn.User()] = key.Type() + " " + base64.StdEncoding.EncodeToString(key.Marshal()) authRequestMap.timestamps[conn.User()] = time.Now() authRequestMap.Unlock() return nil, nil } //Causes "Permission denied (publickey)." for openssh. How can this bubble up to the user? return nil, errors.New("Invalid token/username.") }
// authKey records any incoming request trying to auth with an ssh key func authKey(conn ssh.ConnMetadata, key ssh.PublicKey) (*ssh.Permissions, error) { r := &AuthEvent{ Time: fmt.Sprintf("%d", time.Now().Unix()), AuthType: "sshKey", SrcIP: strings.Split(conn.RemoteAddr().String(), ":")[0], DestIP: extIP, User: conn.User(), TypeData: fmt.Sprintf("ssh-key-type: %s client-version: %s", key.Type(), strconv.QuoteToASCII(string(conn.ClientVersion()))), } h := sha256.New() h.Write(key.Marshal()) r.Credentials = base64.StdEncoding.EncodeToString(h.Sum(nil)) addToBatch(r) return nil, errAuthenticationFailed }
func (pb *permissionsBuilder) Build(processGuid string, index int, metadata ssh.ConnMetadata) (*ssh.Permissions, error) { actual, err := pb.bbsClient.ActualLRPGroupByProcessGuidAndIndex(processGuid, index) if err != nil { return nil, err } desired, err := pb.bbsClient.DesiredLRPByProcessGuid(processGuid) if err != nil { return nil, err } sshRoute, err := getRoutingInfo(desired) if err != nil { return nil, err } logMessage := fmt.Sprintf("Successful remote access by %s", metadata.RemoteAddr().String()) actualLRP, _ := actual.Resolve() return createPermissions(sshRoute, actualLRP, desired.LogGuid, logMessage, index) }
// SCP Public Key authentication check func (a authDB) AuthSCPPublicKey(cmd ssh.ConnMetadata, recvKey ssh.PublicKey) (*ssh.Permissions, error) { // Get the client c := a.findClient(cmd.RemoteAddr().String()) if c == nil { return nil, fmt.Errorf("Unknown host %s", cmd.RemoteAddr().String()) } // Verify there is a key configured goodKey := c.Protocols.SCP.parsedPublicKey if goodKey == nil { return nil, fmt.Errorf("Auth failed") } // Compare keys if bytes.Compare(recvKey.Marshal(), (*goodKey).Marshal()) == 0 { return nil, nil } return nil, fmt.Errorf("Auth failed") }
func (sshClient *sshClient) authLogCallback(conn ssh.ConnMetadata, method string, err error) { if err != nil { if method == "none" && err.Error() == "no auth passed yet" { // In this case, the callback invocation is noise from auth negotiation return } if sshClient.sshServer.support.Config.UseFail2Ban() { clientIPAddress := psiphon.IPAddressFromAddr(conn.RemoteAddr()) if clientIPAddress != "" { LogFail2Ban(clientIPAddress) } } log.WithContextFields(LogFields{"error": err, "method": method}).Error("authentication failed") } else { log.WithContextFields(LogFields{"error": err, "method": method}).Debug("authentication success") } }
// PublicKeyCallback is called when the user tries to authenticate using an SSH public key func (s *Server) PublicKeyCallback(conn ssh.ConnMetadata, key ssh.PublicKey) (*ssh.Permissions, error) { username := conn.User() clientID := conn.RemoteAddr().String() keyText := strings.TrimSpace(string(ssh.MarshalAuthorizedKey(key))) log.Debugf("PublicKeyCallback: %q %q", username, keyText) // sessionID := conn.SessionID() config := s.ClientConfigs[clientID] if config == nil { s.ClientConfigs[clientID] = &ClientConfig{ RemoteUser: username, ImageName: username, Keys: []string{}, AuthenticationMethod: "noauth", AuthenticationAttempts: 0, AuthenticationComment: "", Env: make(envhelper.Environment, 0), } } config = s.ClientConfigs[clientID] config.Keys = append(config.Keys, keyText) return nil, s.CheckConfig(config) }
func (dpa *DiegoProxyAuthenticator) Authenticate(metadata ssh.ConnMetadata, password []byte) (*ssh.Permissions, error) { logger := dpa.logger.Session("authenticate") logger.Info("authentication-starting") defer logger.Info("authentication-finished") if !DiegoUserRegex.MatchString(metadata.User()) { logger.Error("regex-match-fail", InvalidDomainErr) return nil, InvalidDomainErr } if !bytes.Equal(dpa.receptorCreds, password) { logger.Error("invalid-credentials", InvalidCredentialsErr) return nil, InvalidCredentialsErr } guidAndIndex := DiegoUserRegex.FindStringSubmatch(metadata.User()) processGuid := guidAndIndex[1] index, err := strconv.Atoi(guidAndIndex[2]) if err != nil { logger.Error("atoi-failed", err) return nil, err } permissions, err := sshPermissionsFromProcess(processGuid, index, dpa.receptorClient, metadata.RemoteAddr()) if err != nil { logger.Error("building-ssh-permissions-failed", err) } return permissions, err }
func keyAuth(conn ssh.ConnMetadata, key ssh.PublicKey) (*ssh.Permissions, error) { log.Println(conn.RemoteAddr(), "authenticate with", key.Type()) return nil, nil }
func (cfa *CFAuthenticator) Authenticate(metadata ssh.ConnMetadata, password []byte) (*ssh.Permissions, error) { logger := cfa.logger.Session("authenticate") if !CFRealmRegex.Match([]byte(metadata.User())) { return nil, InvalidDomainErr } principal := CFRealmRegex.FindStringSubmatch(metadata.User())[1] if !CFPrincipalRegex.Match([]byte(principal)) { return nil, InvalidCredentialsErr } guidAndIndex := CFPrincipalRegex.FindStringSubmatch(principal) index, err := strconv.Atoi(guidAndIndex[2]) if err != nil { logger.Error("atoi-failed", err) return nil, InvalidCredentialsErr } appGuid := guidAndIndex[1] path := fmt.Sprintf("%s/internal/apps/%s/ssh_access", cfa.ccURL, appGuid) req, err := http.NewRequest("GET", path, nil) if err != nil { logger.Error("creating-request-failed", InvalidRequestErr) return nil, InvalidRequestErr } req.Header.Add("Authorization", string(password)) resp, err := cfa.ccClient.Do(req) if err != nil { logger.Error("fetching-app-failed", err) return nil, err } defer resp.Body.Close() if resp.StatusCode != http.StatusOK { logger.Error("fetching-app-failed", FetchAppFailedErr, lager.Data{ "StatusCode": resp.Status, "ResponseBody": resp.Body, }) return nil, FetchAppFailedErr } var app AppSSHResponse err = json.NewDecoder(resp.Body).Decode(&app) if err != nil { logger.Error("invalid-cc-response", err) return nil, InvalidCCResponse } permissions, err := sshPermissionsFromProcess(app.ProcessGuid, index, cfa.receptorClient, metadata.RemoteAddr()) if err != nil { logger.Error("building-ssh-permissions-failed", err) } return permissions, err }
// KeyboardInteractiveCallback is called after PublicKeyCallback func (s *Server) KeyboardInteractiveCallback(conn ssh.ConnMetadata, challenge ssh.KeyboardInteractiveChallenge) (*ssh.Permissions, error) { username := conn.User() clientID := conn.RemoteAddr().String() log.Debugf("KeyboardInteractiveCallback: %q", username) config := s.ClientConfigs[clientID] if config == nil { s.ClientConfigs[clientID] = &ClientConfig{ RemoteUser: username, ImageName: username, Keys: []string{}, AuthenticationMethod: "noauth", AuthenticationAttempts: 0, AuthenticationComment: "", Env: make(envhelper.Environment, 0), } } config = s.ClientConfigs[clientID] if len(config.Keys) == 0 { log.Warnf("No user keys, continuing with password authentication") return nil, s.CheckConfig(config) } if s.PublicKeyAuthScript == "" { log.Debugf("%d keys received, but no hook script, continuing", len(config.Keys)) return nil, s.CheckConfig(config) } config.AuthenticationAttempts++ log.Debugf("%d keys received, trying to authenticate using publickey hook", len(config.Keys)) var output []byte switch { case strings.HasPrefix(s.PublicKeyAuthScript, "http://"), strings.HasPrefix(s.PublicKeyAuthScript, "https://"): input := struct { Username string `json:"username"` Publickeys []string `json:"publickeys"` }{ Username: username, Publickeys: config.Keys, } resp, body, errs := gorequest.New().Type("json").Post(s.PublicKeyAuthScript).Send(input).End() if len(errs) > 0 { return nil, fmt.Errorf("gorequest errs: %v", errs) } if resp.StatusCode != 200 { return nil, fmt.Errorf("invalid status code: %d", resp.StatusCode) } output = []byte(body) default: script, err := homedir.Expand(s.PublicKeyAuthScript) if err != nil { log.Warnf("Failed to expandUser: %v", err) return nil, err } cmd := exec.Command(script, append([]string{username}, config.Keys...)...) cmd.Env = config.Env.List() // FIXME: redirect stderr to log cmd.Stderr = os.Stderr output, err = cmd.Output() if err != nil { log.Warnf("Failed to execute publickey-auth-script: %v", err) return nil, err } } if err := json.Unmarshal(output, &config); err != nil { log.Warnf("Failed to unmarshal json %q: %v", string(output), err) return nil, err } if err := s.CheckConfig(config); err != nil { return nil, err } // success config.AuthenticationMethod = "publickey" return nil, nil }
// PasswordCallback is called when the user tries to authenticate using a password func (s *Server) PasswordCallback(conn ssh.ConnMetadata, password []byte) (*ssh.Permissions, error) { username := conn.User() clientID := conn.RemoteAddr().String() log.Debugf("PasswordCallback: %q %q", username, password) // map config in the memory config := s.ClientConfigs[clientID] if config == nil { s.ClientConfigs[clientID] = &ClientConfig{ //Allowed: true, RemoteUser: username, ImageName: username, Keys: []string{}, AuthenticationMethod: "noauth", AuthenticationAttempts: 0, AuthenticationComment: "", Env: make(envhelper.Environment, 0), } config = s.ClientConfigs[clientID] } // if there is a password callback if s.PasswordAuthScript == "" { return nil, s.CheckConfig(config) } config.AuthenticationAttempts++ var output []byte switch { case strings.HasPrefix(s.PasswordAuthScript, "http://"), strings.HasPrefix(s.PasswordAuthScript, "https://"): input := struct { Username string `json:"username"` Password string `json:"password"` }{ Username: username, Password: string(password), } resp, body, errs := gorequest.New().Type("json").Post(s.PasswordAuthScript).Send(input).End() if len(errs) > 0 { return nil, fmt.Errorf("gorequest errs: %v", errs) } if resp.StatusCode != 200 { return nil, fmt.Errorf("invalid status code: %d", resp.StatusCode) } output = []byte(body) default: script, err := homedir.Expand(s.PasswordAuthScript) if err != nil { log.Warnf("Failed to expandUser: %v", err) return nil, err } cmd := exec.Command(script, username, string(password)) cmd.Env = config.Env.List() // FIXME: redirect stderr to log cmd.Stderr = os.Stderr output, err = cmd.Output() if err != nil { log.Warnf("Failed to execute password-auth-script: %v", err) return nil, err } } if err := json.Unmarshal(output, &config); err != nil { log.Warnf("Failed to unmarshal json %q: %v", string(output), err) return nil, err } if err := s.CheckConfig(config); err != nil { return nil, err } // success config.AuthenticationMethod = "password" return nil, nil }