Exemple #1
0
// CheckPublicKeyString checks if the given public key string is recognized by SSH.
func CheckPublicKeyString(content string) (_ string, err error) {
	content, err = parseKeyString(content)
	if err != nil {
		return "", err
	}

	content = strings.TrimRight(content, "\n\r")
	if strings.ContainsAny(content, "\n\r") {
		return "", errors.New("only a single line with a single key please")
	}

	// remove any unnecessary whitespace now
	content = strings.TrimSpace(content)

	fields := strings.Fields(content)
	if len(fields) < 2 {
		return "", errors.New("too less fields")
	}

	key, err := base64.StdEncoding.DecodeString(fields[1])
	if err != nil {
		return "", fmt.Errorf("StdEncoding.DecodeString: %v", err)
	}
	pkey, err := ssh.ParsePublicKey([]byte(key))
	if err != nil {
		return "", fmt.Errorf("ParsePublicKey: %v", err)
	}
	log.Trace("Key type: %s", pkey.Type())

	return content, nil
}
Exemple #2
0
// Converts a public key to authorized keys format.
func PublicKeyToAuthorizedKeysFormat(in string) (string, error) {
	s := strings.Replace(strings.Replace(strings.TrimSpace(in), "\r\n", "\n", -1), "\r", "\n", -1)
	lines := strings.Split(s, "\n")
	if len(lines) == 1 {
		publicKey, comment, _, _, err := ssh.ParseAuthorizedKey([]byte(lines[0]))
		if err != nil {
			return "", fmt.Errorf("failed to parse public key from authorized keys format: %v", err)
		}
		encodedKey := base64.StdEncoding.EncodeToString(publicKey.Marshal())
		return fmt.Sprintf("%s %s %s", publicKey.Type(), encodedKey, comment), nil
	} else {
		var encodedKey string
		continuationLine := false
		for _, line := range lines {
			if continuationLine || strings.ContainsAny(line, ":-") {
				continuationLine = strings.HasSuffix(line, "\\")
			} else {
				encodedKey += line
			}
		}
		rawKey, err := base64.StdEncoding.DecodeString(encodedKey)
		fmt.Println(encodedKey)
		if err != nil {
			return "", fmt.Errorf("detected SSH2 format, but contains invalid base64 content: %v", err)
		}
		fmt.Println(string(base64.StdEncoding.EncodeToString(rawKey)))
		publicKey, err := ssh.ParsePublicKey(rawKey)
		if err != nil {
			return "", fmt.Errorf("failed to parse public key from SSH2 format: %v", err)
		}
		newEncodedKey := base64.StdEncoding.EncodeToString(publicKey.Marshal())
		return fmt.Sprintf("%s %s cloug@cloug", publicKey.Type(), newEncodedKey), nil
	}
}
//export c_ParsePublicKey
func c_ParsePublicKey(in []byte) (uint64, int, *C.char) {
	pkey, err := ssh.ParsePublicKey(in)
	if err != nil {
		return IH, ErrorCodeInternal, C.CString(err.Error())
	}
	return uint64(RegisterObject(&pkey)), ErrorCodeSuccess, nil
}
Exemple #4
0
func parseECDSACert(req []byte) (*AddedKey, error) {
	var k ecdsaCertMsg
	if err := ssh.Unmarshal(req, &k); err != nil {
		return nil, err
	}

	pubKey, err := ssh.ParsePublicKey(k.CertBytes)
	if err != nil {
		return nil, err
	}
	cert, ok := pubKey.(*ssh.Certificate)
	if !ok {
		return nil, errors.New("agent: bad ECDSA certificate")
	}

	// An ECDSA publickey as marshaled by ecdsaPublicKey.Marshal() in keys.go
	var ecdsaPub struct {
		Name string
		ID   string
		Key  []byte
	}
	if err := ssh.Unmarshal(cert.Key.Marshal(), &ecdsaPub); err != nil {
		return nil, err
	}

	priv, err := unmarshalECDSA(ecdsaPub.ID, ecdsaPub.Key, k.D)
	if err != nil {
		return nil, err
	}

	return &AddedKey{PrivateKey: priv, Certificate: cert, Comment: k.Comments}, nil
}
Exemple #5
0
// Verify satisfies the ssh.PublicKey interface.
func (k *Key) Verify(data []byte, sig *ssh.Signature) error {
	pubKey, err := ssh.ParsePublicKey(k.Blob)
	if err != nil {
		return fmt.Errorf("agent: bad public key: %v", err)
	}
	return pubKey.Verify(data, sig)
}
Exemple #6
0
// SSHNativeParsePublicKey extracts the key type and length using the golang SSH library.
// NOTE: ed25519 is not supported.
func SSHNativeParsePublicKey(keyLine string) (string, int, error) {
	fields := strings.Fields(keyLine)
	if len(fields) < 2 {
		return "", 0, fmt.Errorf("not enough fields in public key line: %s", string(keyLine))
	}

	raw, err := base64.StdEncoding.DecodeString(fields[1])
	if err != nil {
		return "", 0, err
	}

	pkey, err := ssh.ParsePublicKey(raw)
	if err != nil {
		if strings.Contains(err.Error(), "ssh: unknown key algorithm") {
			return "", 0, ErrKeyUnableVerify{err.Error()}
		}
		return "", 0, fmt.Errorf("ssh.ParsePublicKey: %v", err)
	}

	// The ssh library can parse the key, so next we find out what key exactly we have.
	switch pkey.Type() {
	case ssh.KeyAlgoDSA:
		rawPub := struct {
			Name       string
			P, Q, G, Y *big.Int
		}{}
		if err := ssh.Unmarshal(pkey.Marshal(), &rawPub); err != nil {
			return "", 0, err
		}
		// as per https://bugzilla.mindrot.org/show_bug.cgi?id=1647 we should never
		// see dsa keys != 1024 bit, but as it seems to work, we will not check here
		return "dsa", rawPub.P.BitLen(), nil // use P as per crypto/dsa/dsa.go (is L)
	case ssh.KeyAlgoRSA:
		rawPub := struct {
			Name string
			E    *big.Int
			N    *big.Int
		}{}
		if err := ssh.Unmarshal(pkey.Marshal(), &rawPub); err != nil {
			return "", 0, err
		}
		return "rsa", rawPub.N.BitLen(), nil // use N as per crypto/rsa/rsa.go (is bits)
	case ssh.KeyAlgoECDSA256:
		return "ecdsa", 256, nil
	case ssh.KeyAlgoECDSA384:
		return "ecdsa", 384, nil
	case ssh.KeyAlgoECDSA521:
		return "ecdsa", 521, nil
	case "ssh-ed25519": // TODO replace with ssh constant when available
		return "ed25519", 256, nil
	}
	return "", 0, fmt.Errorf("Unsupported key length detection for type: %s", pkey.Type())
}
Exemple #7
0
func parseEd25519Cert(req []byte) (*AddedKey, error) {
	var k ed25519CertMsg
	if err := ssh.Unmarshal(req, &k); err != nil {
		return nil, err
	}
	pubKey, err := ssh.ParsePublicKey(k.CertBytes)
	if err != nil {
		return nil, err
	}
	priv := ed25519.PrivateKey(k.Priv)
	cert, ok := pubKey.(*ssh.Certificate)
	if !ok {
		return nil, errors.New("agent: bad ED25519 certificate")
	}
	return &AddedKey{PrivateKey: &priv, Certificate: cert, Comment: k.Comments}, nil
}
Exemple #8
0
func (c sshConn) PublicKey() ssh.PublicKey {
	if c.Permissions == nil {
		return nil
	}

	s, ok := c.Permissions.Extensions["pubkey"]
	if !ok {
		return nil
	}

	key, err := ssh.ParsePublicKey([]byte(s))
	if err != nil {
		return nil
	}

	return key
}
Exemple #9
0
/*
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
}
Exemple #10
0
func parseRSACert(req []byte) (*AddedKey, error) {
	var k rsaCertMsg
	if err := ssh.Unmarshal(req, &k); err != nil {
		return nil, err
	}

	pubKey, err := ssh.ParsePublicKey(k.CertBytes)
	if err != nil {
		return nil, err
	}

	cert, ok := pubKey.(*ssh.Certificate)
	if !ok {
		return nil, errors.New("agent: bad RSA certificate")
	}

	// An RSA publickey as marshaled by rsaPublicKey.Marshal() in keys.go
	var rsaPub struct {
		Name string
		E    *big.Int
		N    *big.Int
	}
	if err := ssh.Unmarshal(cert.Key.Marshal(), &rsaPub); err != nil {
		return nil, fmt.Errorf("agent: Unmarshal failed to parse public key: %v", err)
	}

	if rsaPub.E.BitLen() > 30 {
		return nil, errors.New("agent: RSA public exponent too large")
	}

	priv := rsa.PrivateKey{
		PublicKey: rsa.PublicKey{
			E: int(rsaPub.E.Int64()),
			N: rsaPub.N,
		},
		D:      k.D,
		Primes: []*big.Int{k.Q, k.P},
	}
	priv.Precompute()

	return &AddedKey{PrivateKey: &priv, Certificate: cert, Comment: k.Comments}, nil
}
func (h *certRequestHandler) extractCertFromRequest(req *http.Request) (*ssh.Certificate, error) {

	if req.Form["cert"] == nil || len(req.Form["cert"]) == 0 {
		err := errors.New("Please specify exactly one cert request")
		return nil, err
	}

	rawCertRequest, err := base64.StdEncoding.DecodeString(req.Form["cert"][0])
	if err != nil {
		err := errors.New("Unable to base64 decode cert request")
		return nil, err
	}
	pubKey, err := ssh.ParsePublicKey(rawCertRequest)
	if err != nil {
		err := errors.New("Unable to parse cert request")
		return nil, err
	}

	return pubKey.(*ssh.Certificate), nil
}
Exemple #12
0
func verify(a agent.Agent, b string, sFormat string, s string) {
	keys, err := a.List()
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}

	data, err := base64.StdEncoding.DecodeString(b)
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}

	sigData, err := base64.StdEncoding.DecodeString(s)
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}

	sig := &ssh.Signature{sFormat, sigData}

	w := new(tabwriter.Writer)
	// Format in tab-separated columns with a tab stop of 8.
	w.Init(os.Stdout, 0, 8, 0, '\t', 0)

	for i, k := range keys {
		mKey := k.Marshal()
		verifyKey, err := ssh.ParsePublicKey(mKey)
		if err != nil {
			fmt.Println(err.Error())
			os.Exit(1)
		}
		ok := true
		err = verifyKey.Verify(data, sig)
		if err != nil {
			ok = false
		}
		fmt.Fprintf(w, "%02d: verified: %t\n", i, ok)
		w.Flush()
	}
}
Exemple #13
0
func GetFingerPrint(key OpenSSHPublicKey, algo string) (fp string, err error) {
	pubkey, err := ssh.ParsePublicKey(key.key)
	if err != nil {
		return "", errors.New("Cannot Get Fingerprint: Cannot Parse")
	}

	var cs []byte
	switch algo {
	case "md5":
		tmp := md5.Sum(pubkey.Marshal())
		cs = tmp[:]
	case "sha224":
		tmp := sha256.Sum224(pubkey.Marshal())
		cs = tmp[:]
	case "sha256":
		tmp := sha256.Sum256(pubkey.Marshal())
		cs = tmp[:]
	case "sha384":
		tmp := sha512.Sum384(pubkey.Marshal())
		cs = tmp[:]
	case "sha512":
		tmp := sha512.Sum512(pubkey.Marshal())
		cs = tmp[:]
	default:
		tmp := sha256.Sum256(pubkey.Marshal())
		cs = tmp[:]
	}
	switch algo {
	case "md5":
		for i := 0; i < len(cs); i++ {
			fp = fmt.Sprintf("%s%0.2x", fp, cs[i])
			if i != len(cs)-1 {
				fp = fp + ":"
			}
		}
	default:
		fp = base64.StdEncoding.EncodeToString(cs)
	}
	return
}
Exemple #14
0
func computeAwsKeyFingerprint(publicKey *fi.ResourceHolder) (string, error) {
	publicKeyString, err := publicKey.AsString()
	if err != nil {
		return "", fmt.Errorf("error reading SSH public key: %v", err)
	}

	tokens := strings.Split(publicKeyString, " ")
	if len(tokens) < 2 {
		return "", fmt.Errorf("error parsing SSH public key: %s", publicKeyString)
	}

	sshPublicKeyBytes, err := base64.StdEncoding.DecodeString(tokens[1])
	if len(tokens) < 2 {
		return "", fmt.Errorf("error decoding SSH public key: %s", publicKeyString)
	}

	sshPublicKey, err := ssh.ParsePublicKey(sshPublicKeyBytes)
	if err != nil {
		return "", fmt.Errorf("error parsing SSH public key: %v", err)
	}

	der, err := toDER(sshPublicKey)
	if err != nil {
		return "", fmt.Errorf("error computing fingerprint for SSH public key: %v", err)
	}
	h := md5.Sum(der)
	sshKeyFingerprint := fmt.Sprintf("%x", h)

	var colonSeparated bytes.Buffer
	for i := 0; i < len(sshKeyFingerprint); i++ {
		if (i%2) == 0 && i != 0 {
			colonSeparated.WriteByte(':')
		}
		colonSeparated.WriteByte(sshKeyFingerprint[i])
	}

	return colonSeparated.String(), nil
}
Exemple #15
0
func parseDSACert(req []byte) (*AddedKey, error) {
	var k dsaCertMsg
	if err := ssh.Unmarshal(req, &k); err != nil {
		return nil, err
	}
	pubKey, err := ssh.ParsePublicKey(k.CertBytes)
	if err != nil {
		return nil, err
	}
	cert, ok := pubKey.(*ssh.Certificate)
	if !ok {
		return nil, errors.New("agent: bad DSA certificate")
	}

	// A DSA publickey as marshaled by dsaPublicKey.Marshal() in keys.go
	var w struct {
		Name       string
		P, Q, G, Y *big.Int
	}
	if err := ssh.Unmarshal(cert.Key.Marshal(), &w); err != nil {
		return nil, fmt.Errorf("agent: Unmarshal failed to parse public key: %v", err)
	}

	priv := &dsa.PrivateKey{
		PublicKey: dsa.PublicKey{
			Parameters: dsa.Parameters{
				P: w.P,
				Q: w.Q,
				G: w.G,
			},
			Y: w.Y,
		},
		X: k.X,
	}

	return &AddedKey{PrivateKey: priv, Certificate: cert, Comment: k.Comments}, nil
}
func listCerts(c *cli.Context) {

	configPath := c.String("config-file")
	environment := c.String("environment")
	showAll := c.Bool("show-all")

	allConfig := make(map[string]ssh_ca_util.RequesterConfig)
	err := ssh_ca_util.LoadConfig(configPath, &allConfig)
	wrongTypeConfig, err := ssh_ca_util.GetConfigForEnv(environment, &allConfig)
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}
	config := wrongTypeConfig.(ssh_ca_util.RequesterConfig)

	getResp, err := http.Get(config.SignerUrl + "cert/requests")
	if err != nil {
		fmt.Println("Didn't get a valid response", err)
		os.Exit(1)
	}
	getRespBuf, err := ioutil.ReadAll(getResp.Body)
	if err != nil {
		fmt.Println("Error reading response body", err)
		os.Exit(1)
	}
	getResp.Body.Close()
	if getResp.StatusCode != 200 {
		fmt.Println("Error getting listing of certs", string(getRespBuf))
		os.Exit(1)
	}

	certs := make(certRequestResponse)
	json.Unmarshal(getRespBuf, &certs)
	for requestID, respElement := range certs {
		if showAll || !respElement.Signed {
			rawCert, err := base64.StdEncoding.DecodeString(respElement.CertBlob)
			if err != nil {
				fmt.Println("Trouble base64 decoding response:", err, respElement.CertBlob)
				os.Exit(1)
			}
			pubKey, err := ssh.ParsePublicKey(rawCert)
			if err != nil {
				fmt.Println("Trouble parsing response:", err)
				os.Exit(1)
			}
			cert := *pubKey.(*ssh.Certificate)
			env, ok := cert.Extensions["*****@*****.**"]
			if !ok {
				env = "unknown env"
			}
			expired := int64(cert.ValidBefore)-int64(time.Now().Unix()) < 1
			if !expired || showAll {
				expiredMsg := ""
				if expired {
					expiredMsg = ", \033[91mexpired\033[0m"
				}
				fmt.Printf("%d %s[%s, %d/%d%s]: %s - %s\n",
					respElement.Serial,
					requestID,
					env,
					respElement.NumSignatures,
					respElement.SignaturesRequired,
					expiredMsg,
					cert.KeyId,
					cert.Extensions["*****@*****.**"],
				)
			}
		}
	}
}
Exemple #17
0
func ValidateOpenSSHPublicKey(key OpenSSHPublicKey) error {
	_, err := ssh.ParsePublicKey(key.key)
	return err
}
Exemple #18
0
func ClonePublicKey(key ssh.PublicKey) (ssh.PublicKey, error) {
	return ssh.ParsePublicKey(key.Marshal())
}
func signCert(c *cli.Context) {
	configPath := c.String("config-file")
	allConfig := make(map[string]ssh_ca_util.SignerConfig)
	err := ssh_ca_util.LoadConfig(configPath, &allConfig)
	if err != nil {
		fmt.Println("Load Config failed:", err)
		os.Exit(1)
	}

	certRequestID := c.String("cert-request-id")
	if certRequestID == "" {
		certRequestID = c.Args().First()
		if certRequestID == "" {
			fmt.Println("Specify a cert-request-id")
			os.Exit(1)
		}
	}
	environment := c.String("environment")
	wrongTypeConfig, err := ssh_ca_util.GetConfigForEnv(environment, &allConfig)
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}
	config := wrongTypeConfig.(ssh_ca_util.SignerConfig)

	conn, err := net.Dial("unix", os.Getenv("SSH_AUTH_SOCK"))
	if err != nil {
		fmt.Println("Dial failed:", err)
		os.Exit(1)
	}

	signer, err := ssh_ca_util.GetSignerForFingerprint(config.KeyFingerprint, conn)
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}

	requestParameters := make(url.Values)
	requestParameters["certRequestId"] = make([]string, 1)
	requestParameters["certRequestId"][0] = certRequestID
	getResp, err := http.Get(config.SignerUrl + "cert/requests?" + requestParameters.Encode())
	if err != nil {
		fmt.Println("Didn't get a valid response", err)
		os.Exit(1)
	}
	getRespBuf, err := ioutil.ReadAll(getResp.Body)
	if err != nil {
		fmt.Println("Error reading response body", err)
		os.Exit(1)
	}
	getResp.Body.Close()
	if getResp.StatusCode != 200 {
		fmt.Println("Error getting that request id:", string(getRespBuf))
		os.Exit(1)
	}
	getResponse := make(certRequestResponse)
	err = json.Unmarshal(getRespBuf, &getResponse)
	if err != nil {
		fmt.Println("Unable to unmarshall response", err)
		os.Exit(1)
	}
	if getResponse[certRequestID].Signed {
		fmt.Println("Certificate already signed. Thanks for trying.")
		os.Exit(0)
	}
	rawCert, err := base64.StdEncoding.DecodeString(getResponse[certRequestID].CertBlob)
	if err != nil {
		fmt.Println("Trouble base64 decoding response", err)
		os.Exit(1)
	}
	pubKey, err := ssh.ParsePublicKey(rawCert)
	if err != nil {
		fmt.Println("Trouble parsing response", err)
		os.Exit(1)
	}
	cert := *pubKey.(*ssh.Certificate)
	ssh_ca_util.PrintForInspection(cert)
	fmt.Printf("Type 'yes' if you'd like to sign this cert request ")
	reader := bufio.NewReader(os.Stdin)
	text, _ := reader.ReadString('\n')
	text = strings.TrimSpace(text)
	if text != "yes" && text != "YES" {
		os.Exit(0)
	}

	err = cert.SignCert(rand.Reader, signer)
	if err != nil {
		fmt.Println("Error signing:", err)
		os.Exit(1)
	}

	request := ssh_ca_client.MakeSigningRequest(cert, certRequestID, config)
	requestWebParameters := request.BuildWebRequest()
	err = request.PostToWeb(requestWebParameters)
	if err != nil {
		fmt.Println("Error sending in +1:", err)
		os.Exit(1)
	} else {
		fmt.Println("Signature accepted by server.")
	}

}
Exemple #20
0
/*
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
}