コード例 #1
0
ファイル: usercache.go プロジェクト: nathanpalmer/hologram
/*
Update() searches LDAP for the current user set that supports
the necessary properties for Hologram.

TODO: call this at some point during verification failure so that keys that have
been recently added to LDAP work, instead of requiring a server restart.
*/
func (luc *ldapUserCache) Update() error {
	start := time.Now()
	filter := "(sshPublicKey=*)"
	searchRequest := ldap.NewSearchRequest(
		luc.baseDN,
		ldap.ScopeWholeSubtree, ldap.NeverDerefAliases,
		0, 0, false,
		filter, []string{"sshPublicKey", luc.userAttr},
		nil,
	)

	searchResult, err := luc.server.Search(searchRequest)
	if err != nil {
		return err
	}

	for _, entry := range searchResult.Entries {
		username := entry.GetAttributeValue(luc.userAttr)
		userKeys := []ssh.PublicKey{}
		for _, eachKey := range entry.GetAttributeValues("sshPublicKey") {
			sshKeyBytes, _ := base64.StdEncoding.DecodeString(eachKey)
			userSSHKey, err := ssh.ParsePublicKey(sshKeyBytes)
			if err != nil {
				userSSHKey, _, _, _, err = ssh.ParseAuthorizedKey([]byte(eachKey))
				if err != nil {
					log.Warning("SSH key parsing for user %s failed (key was '%s')! This key will not be added into LDAP.", username, eachKey)
					continue
				}
			}

			userKeys = append(userKeys, userSSHKey)
		}

		luc.users[username] = &User{
			SSHKeys:  userKeys,
			Username: username,
		}

		log.Debug("Information on %s (re-)generated.", username)
	}

	log.Debug("LDAP information re-cached.")
	luc.stats.Timing(1.0, "ldapCacheUpdate", time.Since(start))
	return nil
}
コード例 #2
0
ファイル: server.go プロジェクト: graphaelli/hologram
/*
HandleServerRequest handles the flow for messages that this server
accepts from clients.
*/
func (sm *server) HandleServerRequest(m protocol.MessageReadWriteCloser, r *protocol.ServerRequest) {
	if assumeRoleMsg := r.GetAssumeRole(); assumeRoleMsg != nil {
		log.Debug("Handling an assumeRole request.")
		sm.stats.Counter(1.0, "messages.assumeRole", 1)

		role := assumeRoleMsg.GetRole()

		user, err := sm.SSHChallenge(m)

		if err != nil {
			log.Errorf("Error trying to handle AssumeRole: %s", err.Error())
			m.Close()
			return
		}

		if user != nil {
			creds, err := sm.credentials.AssumeRole(user, role, sm.enableLDAPRoles)
			if err != nil {
				// error message from Amazon, so forward that on to the client
				errStr := err.Error()
				errMsg := &protocol.Message{
					Error: &errStr,
				}
				log.Errorf("Error from AWS for AssumeRole: %s", err.Error())
				m.Write(errMsg)
				sm.stats.Counter(1.0, "errors.assumeRole", 1)
				//m.Close()
				return
			}
			m.Write(makeCredsResponse(creds))
			return
		}
	} else if getUserCredentialsMsg := r.GetGetUserCredentials(); getUserCredentialsMsg != nil {
		sm.stats.Counter(1.0, "messages.getUserCredentialsMsg", 1)
		user, err := sm.SSHChallenge(m)
		if err != nil {
			log.Errorf("Error trying to handle GetUserCredentials: %s", err.Error())
			m.Close()
			return
		}

		if user != nil {
			creds, err := sm.credentials.AssumeRole(user, sm.DefaultRole, sm.enableLDAPRoles)
			if err != nil {
				log.Errorf("Error trying to handle GetUserCredentials: %s", err.Error())
				m.Close()
				return
			}
			m.Write(makeCredsResponse(creds))
			return
		}
	} else if addSSHKeyMsg := r.GetAddSSHkey(); addSSHKeyMsg != nil {
		sm.stats.Counter(1.0, "messages.addSSHKeyMsg", 1)

		// Search for the user specified in this request.
		sr := ldap.NewSearchRequest(
			sm.baseDN,
			ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0, false,
			fmt.Sprintf("(%s=%s)", sm.userAttr, addSSHKeyMsg.GetUsername()),
			[]string{"sshPublicKey", sm.userAttr, "userPassword"},
			nil)

		user, err := sm.ldapServer.Search(sr)
		if err != nil {
			log.Errorf("Error trying to handle addSSHKeyMsg: %s", err.Error())
			return
		}

		if len(user.Entries) == 0 {
			log.Errorf("User %s not found!", addSSHKeyMsg.GetUsername())
			return
		}

		// Check their password.
		password := user.Entries[0].GetAttributeValue("userPassword")
		if password != addSSHKeyMsg.GetPasswordhash() {
			log.Errorf("Provided password for user %s does not match %s!", addSSHKeyMsg.GetUsername(), password)
			return
		}

		// Check to see if this SSH key already exists.
		for _, k := range user.Entries[0].GetAttributeValues("sshPublicKey") {
			if k == addSSHKeyMsg.GetSshkeybytes() {
				log.Warning("User %s already has this SSH key. Doing nothing.", addSSHKeyMsg.GetUsername())
				successMsg := &protocol.Message{Success: &protocol.Success{}}
				m.Write(successMsg)
				return
			}
		}

		mr := ldap.NewModifyRequest(user.Entries[0].DN)
		mr.Add("sshPublicKey", []string{addSSHKeyMsg.GetSshkeybytes()})
		err = sm.ldapServer.Modify(mr)
		if err != nil {
			log.Errorf("Could not modify LDAP user: %s", err.Error())
			return
		}

		successMsg := &protocol.Message{Success: &protocol.Success{}}
		m.Write(successMsg)
		return
	}
}
コード例 #3
0
ファイル: usercache.go プロジェクト: graphaelli/hologram
/*
Update() searches LDAP for the current user set that supports
the necessary properties for Hologram.

TODO: call this at some point during verification failure so that keys that have
been recently added to LDAP work, instead of requiring a server restart.
*/
func (luc *ldapUserCache) Update() error {
	start := time.Now()
	if luc.enableLDAPRoles {
		groupSearchRequest := ldap.NewSearchRequest(
			luc.baseDN,
			ldap.ScopeWholeSubtree, ldap.NeverDerefAliases,
			0, 0, false,
			"(objectClass=groupOfNames)",
			[]string{luc.roleAttribute},
			nil,
		)

		groupSearchResult, err := luc.server.Search(groupSearchRequest)
		if err != nil {
			return err
		}

		for _, entry := range groupSearchResult.Entries {
			dn := entry.DN
			arns := entry.GetAttributeValues(luc.roleAttribute)
			log.Debug("Adding %s to %s", arns, dn)
			luc.groups[dn] = arns
		}
	}

	filter := "(sshPublicKey=*)"
	searchRequest := ldap.NewSearchRequest(
		luc.baseDN,
		ldap.ScopeWholeSubtree, ldap.NeverDerefAliases,
		0, 0, false,
		filter, []string{"sshPublicKey", luc.userAttr, "memberOf"},
		nil,
	)

	searchResult, err := luc.server.Search(searchRequest)
	if err != nil {
		return err
	}
	for _, entry := range searchResult.Entries {
		username := entry.GetAttributeValue(luc.userAttr)
		userKeys := []ssh.PublicKey{}
		for _, eachKey := range entry.GetAttributeValues("sshPublicKey") {
			sshKeyBytes, _ := base64.StdEncoding.DecodeString(eachKey)
			userSSHKey, err := ssh.ParsePublicKey(sshKeyBytes)
			if err != nil {
				userSSHKey, _, _, _, err = ssh.ParseAuthorizedKey([]byte(eachKey))
				if err != nil {
					log.Warning("SSH key parsing for user %s failed (key was '%s')! This key will not be added into LDAP.", username, eachKey)
					continue
				}
			}

			userKeys = append(userKeys, userSSHKey)
		}

		arns := []string{}
		if luc.enableLDAPRoles {
			for _, groupDN := range entry.GetAttributeValues("memberOf") {
				log.Debug(groupDN)
				arns = append(arns, luc.groups[groupDN]...)
			}
		}

		luc.users[username] = &User{
			SSHKeys:  userKeys,
			Username: username,
			ARNs:     arns,
		}

		log.Debug("Information on %s (re-)generated.", username)
	}

	log.Debug("LDAP information re-cached.")
	luc.stats.Timing(1.0, "ldapCacheUpdate", time.Since(start))
	return nil
}