// handleRenew handles the auth/token/renew/id path for renewal of tokens. // This is used to prevent token expiration and revocation. func (ts *TokenStore) handleRenew( req *logical.Request, data *framework.FieldData) (*logical.Response, error) { id := data.Get("token").(string) if id == "" { id = data.Get("urltoken").(string) if id == "" { return logical.ErrorResponse("missing token ID"), logical.ErrInvalidRequest } } incrementRaw := data.Get("increment").(int) // Convert the increment increment := time.Duration(incrementRaw) * time.Second // Lookup the token te, err := ts.Lookup(id) if err != nil { return logical.ErrorResponse(err.Error()), logical.ErrInvalidRequest } // Verify the token exists if te == nil { return logical.ErrorResponse("token not found"), logical.ErrInvalidRequest } // Renew the token and its children return ts.expiration.RenewToken(req, te.Path, te.ID, increment) }
func pathPolicyDelete( req *logical.Request, d *framework.FieldData) (*logical.Response, error) { name := d.Get("name").(string) p, err := getPolicy(req, name) if err != nil { return logical.ErrorResponse(fmt.Sprintf("error looking up policy %s, error is %s", name, err)), err } if p == nil { return logical.ErrorResponse(fmt.Sprintf("no such key %s", name)), logical.ErrInvalidRequest } if !p.DeletionAllowed { return logical.ErrorResponse(fmt.Sprintf("'allow_deletion' config value is not set")), logical.ErrInvalidRequest } err = req.Storage.Delete("policy/" + name) if err != nil { return logical.ErrorResponse(fmt.Sprintf("error deleting policy %s: %s", name, err)), err } err = req.Storage.Delete("archive/" + name) if err != nil { return logical.ErrorResponse(fmt.Sprintf("error deleting archive %s: %s", name, err)), err } return nil, nil }
func (b *backend) secretAccessKeysAndTokenCreate(s logical.Storage, displayName, policyName, policy string, lifeTimeInSeconds *int64) (*logical.Response, error) { STSClient, err := clientSTS(s) if err != nil { return logical.ErrorResponse(err.Error()), nil } username := genUsername(displayName, policyName) tokenResp, err := STSClient.GetFederationToken( &sts.GetFederationTokenInput{ Name: aws.String(username), Policy: aws.String(policy), DurationSeconds: lifeTimeInSeconds, }) if err != nil { return logical.ErrorResponse(fmt.Sprintf( "Error generating STS keys: %s", err)), nil } // Return the info! return b.Secret(SecretAccessKeyType).Response(map[string]interface{}{ "access_key": *tokenResp.Credentials.AccessKeyId, "secret_key": *tokenResp.Credentials.SecretAccessKey, "security_token": *tokenResp.Credentials.SessionToken, }, map[string]interface{}{ "username": username, "policy": policy, "is_sts": true, }), nil }
func (b *backend) getGenerationParams( data *framework.FieldData, ) (exported bool, format string, role *roleEntry, errorResp *logical.Response) { exportedStr := data.Get("exported").(string) switch exportedStr { case "exported": exported = true case "internal": default: errorResp = logical.ErrorResponse( `The "exported" path parameter must be "internal" or "exported"`) return } format = getFormat(data) if format == "" { errorResp = logical.ErrorResponse( `The "format" path parameter must be "pem", "der", or "pem_bundle"`) return } role = &roleEntry{ TTL: data.Get("ttl").(string), KeyType: data.Get("key_type").(string), KeyBits: data.Get("key_bits").(int), AllowLocalhost: true, AllowAnyName: true, AllowIPSANs: true, EnforceHostnames: false, } errorResp = validateKeyTypeLength(role.KeyType, role.KeyBits) return }
// handleRenew handles the auth/token/renew/id path for renewal of tokens. // This is used to prevent token expiration and revocation. func (ts *TokenStore) handleRenew( req *logical.Request, data *framework.FieldData) (*logical.Response, error) { id := data.Get("token").(string) if id == "" { return logical.ErrorResponse("missing token ID"), logical.ErrInvalidRequest } incrementRaw := data.Get("increment").(int) // Convert the increment increment := time.Duration(incrementRaw) * time.Second // Lookup the token out, err := ts.Lookup(id) if err != nil { return logical.ErrorResponse(err.Error()), logical.ErrInvalidRequest } // Verify the token exists if out == nil { return logical.ErrorResponse("token not found"), logical.ErrInvalidRequest } // Revoke the token and its children auth, err := ts.expiration.RenewToken(out.Path, out.ID, increment) if err != nil { return logical.ErrorResponse(err.Error()), logical.ErrInvalidRequest } // Generate the response resp := &logical.Response{ Auth: auth, } return resp, nil }
// handleEnableAuth is used to enable a new credential backend func (b *SystemBackend) handleEnableAuth( req *logical.Request, data *framework.FieldData) (*logical.Response, error) { // Get all the options path := data.Get("path").(string) logicalType := data.Get("type").(string) description := data.Get("description").(string) if logicalType == "" { return logical.ErrorResponse( "backend type must be specified as a string"), logical.ErrInvalidRequest } // Create the mount entry me := &MountEntry{ Path: path, Type: logicalType, Description: description, } // Attempt enabling if err := b.Core.enableCredential(me); err != nil { b.Backend.Logger().Printf("[ERR] sys: enable auth %#v failed: %v", me, err) return logical.ErrorResponse(err.Error()), logical.ErrInvalidRequest } return nil, nil }
// handleEnableAudit is used to enable a new audit backend func (b *SystemBackend) handleEnableAudit( req *logical.Request, data *framework.FieldData) (*logical.Response, error) { // Get all the options path := data.Get("path").(string) backendType := data.Get("type").(string) description := data.Get("description").(string) options := data.Get("options").(map[string]interface{}) optionMap := make(map[string]string) for k, v := range options { vStr, ok := v.(string) if !ok { return logical.ErrorResponse("options must be string valued"), logical.ErrInvalidRequest } optionMap[k] = vStr } // Create the mount entry me := &MountEntry{ Path: path, Type: backendType, Description: description, Options: optionMap, } // Attempt enabling if err := b.Core.enableAudit(me); err != nil { b.Backend.Logger().Printf("[ERR] sys: enable audit %#v failed: %v", me, err) return logical.ErrorResponse(err.Error()), logical.ErrInvalidRequest } return nil, nil }
func (b *backend) pathConnectionWrite( req *logical.Request, data *framework.FieldData) (*logical.Response, error) { connString := data.Get("value").(string) // Verify the string db, err := sql.Open("postgres", connString) if err != nil { return logical.ErrorResponse(fmt.Sprintf( "Error validating connection info: %s", err)), nil } defer db.Close() if err := db.Ping(); err != nil { return logical.ErrorResponse(fmt.Sprintf( "Error validating connection info: %s", err)), nil } // Store it entry, err := logical.StorageEntryJSON("config/connection", connString) if err != nil { return nil, err } if err := req.Storage.Put(entry); err != nil { return nil, err } // Reset the DB connection b.ResetDB() return nil, nil }
func (b *backend) pathCRLRead( req *logical.Request, d *framework.FieldData) (*logical.Response, error) { name := strings.ToLower(d.Get("name").(string)) if name == "" { return logical.ErrorResponse(`"name" parameter must be set`), nil } b.crlUpdateMutex.RLock() defer b.crlUpdateMutex.RUnlock() var retData map[string]interface{} crl, ok := b.crls[name] if !ok { return logical.ErrorResponse(fmt.Sprintf( "no such CRL %s", name, )), nil } retData = structs.New(&crl).Map() return &logical.Response{ Data: retData, }, nil }
func (b *backend) pathCRLDelete( req *logical.Request, d *framework.FieldData) (*logical.Response, error) { name := strings.ToLower(d.Get("name").(string)) if name == "" { return logical.ErrorResponse(`"name" parameter cannot be empty`), nil } b.crlUpdateMutex.Lock() defer b.crlUpdateMutex.Unlock() _, ok := b.crls[name] if !ok { return logical.ErrorResponse(fmt.Sprintf( "no such CRL %s", name, )), nil } err := req.Storage.Delete("crls/" + name) if err != nil { return logical.ErrorResponse(fmt.Sprintf( "error deleting crl %s: %v", name, err), ), nil } delete(b.crls, name) return nil, nil }
// handleRawRead is used to read directly from the barrier func (b *SystemBackend) handleRawRead( req *logical.Request, data *framework.FieldData) (*logical.Response, error) { path := data.Get("path").(string) // Prevent access of protected paths for _, p := range protectedPaths { if strings.HasPrefix(path, p) { err := fmt.Sprintf("cannot read '%s'", path) return logical.ErrorResponse(err), logical.ErrInvalidRequest } } entry, err := b.Core.barrier.Get(path) if err != nil { return logical.ErrorResponse(err.Error()), logical.ErrInvalidRequest } if entry == nil { return nil, nil } resp := &logical.Response{ Data: map[string]interface{}{ "value": string(entry.Value), }, } return resp, nil }
func (b *backend) pathConfigZeroAddressWrite(req *logical.Request, d *framework.FieldData) (*logical.Response, error) { roleNames := d.Get("roles").(string) if roleNames == "" { return logical.ErrorResponse("Missing roles"), nil } // Check if the roles listed actually exist in the backend roles := strings.Split(roleNames, ",") for _, item := range roles { role, err := b.getRole(req.Storage, item) if err != nil { return nil, err } if role == nil { return logical.ErrorResponse(fmt.Sprintf("Role [%s] does not exist", item)), nil } } err := b.putZeroAddressRoles(req.Storage, roles) if err != nil { return nil, err } return nil, nil }
// handleLookup handles the auth/token/lookup/id path for querying information about // a particular token. This can be used to see which policies are applicable. func (ts *TokenStore) handleLookup( req *logical.Request, data *framework.FieldData) (*logical.Response, error) { id := data.Get("token").(string) if id == "" { id = req.ClientToken } if id == "" { return logical.ErrorResponse("missing token ID"), logical.ErrInvalidRequest } // Lookup the token out, err := ts.Lookup(id) if err != nil { return logical.ErrorResponse(err.Error()), logical.ErrInvalidRequest } if out == nil { return logical.ErrorResponse("bad token"), logical.ErrPermissionDenied } // Generate a response. We purposely omit the parent reference otherwise // you could escalate your privileges. resp := &logical.Response{ Data: map[string]interface{}{ "id": out.ID, "accessor": out.Accessor, "policies": out.Policies, "path": out.Path, "meta": out.Meta, "display_name": out.DisplayName, "num_uses": out.NumUses, "orphan": false, "creation_time": int64(out.CreationTime), "creation_ttl": int64(out.TTL.Seconds()), "ttl": int64(0), "role": out.Role, }, } if out.Parent == "" { resp.Data["orphan"] = true } // Fetch the last renewal time leaseTimes, err := ts.expiration.FetchLeaseTimesByToken(out.Path, out.ID) if err != nil { return logical.ErrorResponse(err.Error()), logical.ErrInvalidRequest } if leaseTimes != nil { if !leaseTimes.LastRenewalTime.IsZero() { resp.Data["last_renewal_time"] = leaseTimes.LastRenewalTime.Unix() } if !leaseTimes.ExpireTime.IsZero() { resp.Data["ttl"] = int64(leaseTimes.ExpireTime.Sub(time.Now().Round(time.Second)).Seconds()) } } return resp, nil }
func (b *backend) pathConfigLeaseWrite( req *logical.Request, d *framework.FieldData) (*logical.Response, error) { ttlRaw := d.Get("ttl").(string) ttlMaxRaw := d.Get("max_ttl").(string) if len(ttlMaxRaw) == 0 { ttlMaxRaw = d.Get("ttl_max").(string) } ttl, err := time.ParseDuration(ttlRaw) if err != nil { return logical.ErrorResponse(fmt.Sprintf( "Invalid ttl: %s", err)), nil } ttlMax, err := time.ParseDuration(ttlMaxRaw) if err != nil { return logical.ErrorResponse(fmt.Sprintf( "Invalid max_ttl: %s", err)), nil } // Store it entry, err := logical.StorageEntryJSON("config/lease", &configLease{ TTL: ttl, TTLMax: ttlMax, }) if err != nil { return nil, err } if err := req.Storage.Put(entry); err != nil { return nil, err } return nil, nil }
func (b *backend) pathSTSRead( req *logical.Request, d *framework.FieldData) (*logical.Response, error) { policyName := d.Get("name").(string) ttl := int64(d.Get("ttl").(int)) // Read the policy policy, err := req.Storage.Get("policy/" + policyName) if err != nil { return nil, fmt.Errorf("error retrieving role: %s", err) } if policy == nil { return logical.ErrorResponse(fmt.Sprintf( "Role '%s' not found", policyName)), nil } policyValue := string(policy.Value) if strings.HasPrefix(policyValue, "arn:") { return logical.ErrorResponse( "Can't generate STS credentials for a managed policy; use an inline policy instead"), logical.ErrInvalidRequest } // Use the helper to create the secret return b.secretTokenCreate( req.Storage, req.DisplayName, policyName, policyValue, &ttl, ) }
// handleRevokeOrphan handles the auth/token/revoke-orphan/id path for revocation of tokens // in a way that leaves child tokens orphaned. Normally, using sys/revoke/leaseID will revoke // the token and all children. func (ts *TokenStore) handleRevokeOrphan( req *logical.Request, data *framework.FieldData) (*logical.Response, error) { // Parse the id id := data.Get("token").(string) if id == "" { return logical.ErrorResponse("missing token ID"), logical.ErrInvalidRequest } parent, err := ts.Lookup(req.ClientToken) if err != nil { return logical.ErrorResponse(fmt.Sprintf("parent token lookup failed: %s", err.Error())), logical.ErrInvalidRequest } if parent == nil { return logical.ErrorResponse("parent token lookup failed"), logical.ErrInvalidRequest } // Check if the parent policy is root isRoot := strListContains(parent.Policies, "root") if !isRoot { return logical.ErrorResponse("root required to revoke and orphan"), logical.ErrInvalidRequest } // Revoke and orphan if err := ts.Revoke(id); err != nil { return logical.ErrorResponse(err.Error()), logical.ErrInvalidRequest } return nil, nil }
func (b *backend) pathLeaseWrite( req *logical.Request, d *framework.FieldData) (*logical.Response, error) { leaseRaw := d.Get("lease").(string) leaseMaxRaw := d.Get("lease_max").(string) lease, err := time.ParseDuration(leaseRaw) if err != nil { return logical.ErrorResponse(fmt.Sprintf( "Invalid lease: %s", err)), nil } leaseMax, err := time.ParseDuration(leaseMaxRaw) if err != nil { return logical.ErrorResponse(fmt.Sprintf( "Invalid lease: %s", err)), nil } // Store it entry, err := logical.StorageEntryJSON("config/lease", &configLease{ Lease: lease, LeaseMax: leaseMax, }) if err != nil { return nil, err } if err := req.Storage.Put(entry); err != nil { return nil, err } return nil, nil }
// handleRevokeOrphan handles the auth/token/revoke-orphan/id path for revocation of tokens // in a way that leaves child tokens orphaned. Normally, using sys/revoke/leaseID will revoke // the token and all children. func (ts *TokenStore) handleRevokeOrphan( req *logical.Request, data *framework.FieldData) (*logical.Response, error) { // Parse the id id := data.Get("token").(string) if id == "" { return logical.ErrorResponse("missing token ID"), logical.ErrInvalidRequest } parent, err := ts.Lookup(req.ClientToken) if err != nil { return logical.ErrorResponse(fmt.Sprintf("parent token lookup failed: %s", err.Error())), logical.ErrInvalidRequest } if parent == nil { return logical.ErrorResponse("parent token lookup failed"), logical.ErrInvalidRequest } // Check if the client token has sudo/root privileges for the requested path isSudo := ts.System().SudoPrivilege(req.MountPoint+req.Path, req.ClientToken) if !isSudo { return logical.ErrorResponse("root or sudo privileges required to revoke and orphan"), logical.ErrInvalidRequest } // Revoke and orphan if err := ts.Revoke(id); err != nil { return logical.ErrorResponse(err.Error()), logical.ErrInvalidRequest } return nil, nil }
// pathConfigCertificateCreateUpdate is used to register an AWS Public Key that is // used to verify the PKCS#7 signature of the instance identity document. func (b *backend) pathConfigCertificateCreateUpdate( req *logical.Request, data *framework.FieldData) (*logical.Response, error) { certName := data.Get("cert_name").(string) if certName == "" { return logical.ErrorResponse("missing cert_name"), nil } b.configMutex.Lock() defer b.configMutex.Unlock() // Check if there is already a certificate entry registered. certEntry, err := b.nonLockedAWSPublicCertificateEntry(req.Storage, certName) if err != nil { return nil, err } if certEntry == nil { certEntry = &awsPublicCert{} } // Check if the value is provided by the client. certStrData, ok := data.GetOk("aws_public_cert") if ok { if certBytes, err := base64.StdEncoding.DecodeString(certStrData.(string)); err == nil { certEntry.AWSPublicCert = string(certBytes) } else { certEntry.AWSPublicCert = certStrData.(string) } } else { // aws_public_cert should be supplied for both create and update operations. // If it is not provided, throw an error. return logical.ErrorResponse("missing aws_public_cert"), nil } // If explicitly set to empty string, error out. if certEntry.AWSPublicCert == "" { return logical.ErrorResponse("invalid aws_public_cert"), nil } // Verify the certificate by decoding it and parsing it. publicCert, err := decodePEMAndParseCertificate(certEntry.AWSPublicCert) if err != nil { return nil, err } if publicCert == nil { return logical.ErrorResponse("invalid certificate; failed to decode and parse certificate"), nil } // Ensure that we have not // If none of the checks fail, save the provided certificate. entry, err := logical.StorageEntryJSON("config/certificate/"+certName, certEntry) if err != nil { return nil, err } if err := req.Storage.Put(entry); err != nil { return nil, err } return nil, nil }
// Registers a new role with the backend func (b *backend) pathRoleUpdate(req *logical.Request, d *framework.FieldData) (*logical.Response, error) { name := d.Get("name").(string) if name == "" { return logical.ErrorResponse("missing name"), nil } tags := d.Get("tags").(string) rawVHosts := d.Get("vhosts").(string) if tags == "" && rawVHosts == "" { return logical.ErrorResponse("both tags and vhosts not specified"), nil } var vhosts map[string]vhostPermission if len(rawVHosts) > 0 { err := json.Unmarshal([]byte(rawVHosts), &vhosts) if err != nil { return logical.ErrorResponse(fmt.Sprintf("failed to unmarshal vhosts: %s", err)), nil } } // Store it entry, err := logical.StorageEntryJSON("role/"+name, &roleEntry{ Tags: tags, VHosts: vhosts, }) if err != nil { return nil, err } if err := req.Storage.Put(entry); err != nil { return nil, err } return nil, nil }
func validateKeyTypeLength(keyType string, keyBits int) *logical.Response { switch keyType { case "rsa": switch keyBits { case 2048: case 4096: case 8192: default: return logical.ErrorResponse(fmt.Sprintf( "unsupported bit length for RSA key: %d", keyBits)) } case "ec": switch keyBits { case 224: case 256: case 384: case 521: default: return logical.ErrorResponse(fmt.Sprintf( "unsupported bit length for EC key: %d", keyBits)) } default: return logical.ErrorResponse(fmt.Sprintf( "unknown key type %s", keyType)) } return nil }
// handleMount is used to mount a new path func (b *SystemBackend) handleMount( req *logical.Request, data *framework.FieldData) (*logical.Response, error) { // Get all the options path := data.Get("path").(string) logicalType := data.Get("type").(string) description := data.Get("description").(string) if logicalType == "" { return logical.ErrorResponse( "backend type must be specified as a string"), logical.ErrInvalidRequest } // Create the mount entry me := &MountEntry{ Path: path, Type: logicalType, Description: description, } // Attempt mount if err := b.Core.mount(me); err != nil { return logical.ErrorResponse(err.Error()), logical.ErrInvalidRequest } return nil, nil }
func (b *backend) pathKeysWrite(req *logical.Request, d *framework.FieldData) (*logical.Response, error) { keyName := d.Get("key_name").(string) if keyName == "" { return logical.ErrorResponse("Missing key_name"), nil } keyString := d.Get("key").(string) // Check if the key provided is infact a private key signer, err := ssh.ParsePrivateKey([]byte(keyString)) if err != nil || signer == nil { return logical.ErrorResponse("Invalid key"), nil } if keyString == "" { return logical.ErrorResponse("Missing key"), nil } keyPath := fmt.Sprintf("keys/%s", keyName) // Store the key entry, err := logical.StorageEntryJSON(keyPath, map[string]interface{}{ "key": keyString, }) if err != nil { return nil, err } if err := req.Storage.Put(entry); err != nil { return nil, err } return nil, nil }
func (b *backend) pathConnectionWrite( req *logical.Request, data *framework.FieldData) (*logical.Response, error) { connValue := data.Get("value").(string) connURL := data.Get("connection_url").(string) if connURL == "" { if connValue == "" { return logical.ErrorResponse("connection_url parameter must be supplied"), nil } else { connURL = connValue } } maxOpenConns := data.Get("max_open_connections").(int) if maxOpenConns == 0 { maxOpenConns = 2 } maxIdleConns := data.Get("max_idle_connections").(int) if maxIdleConns == 0 { maxIdleConns = maxOpenConns } if maxIdleConns > maxOpenConns { maxIdleConns = maxOpenConns } // Don't check the connection_url if verification is disabled verifyConnection := data.Get("verify_connection").(bool) if verifyConnection { // Verify the string db, err := sql.Open("postgres", connURL) if err != nil { return logical.ErrorResponse(fmt.Sprintf( "Error validating connection info: %s", err)), nil } defer db.Close() if err := db.Ping(); err != nil { return logical.ErrorResponse(fmt.Sprintf( "Error validating connection info: %s", err)), nil } } // Store it entry, err := logical.StorageEntryJSON("config/connection", connectionConfig{ ConnectionString: connValue, ConnectionURL: connURL, MaxOpenConnections: maxOpenConns, MaxIdleConnections: maxIdleConns, }) if err != nil { return nil, err } if err := req.Storage.Put(entry); err != nil { return nil, err } // Reset the DB connection b.ResetDB() return nil, nil }
// handleLookup handles the auth/token/lookup/id path for querying information about // a particular token. This can be used to see which policies are applicable. func (ts *TokenStore) handleLookup( req *logical.Request, data *framework.FieldData) (*logical.Response, error) { id := data.Get("token").(string) if id == "" { id = req.ClientToken } if id == "" { return logical.ErrorResponse("missing token ID"), logical.ErrInvalidRequest } // Lookup the token out, err := ts.Lookup(id) if err != nil { return logical.ErrorResponse(err.Error()), logical.ErrInvalidRequest } // Fast-path the not found case if out == nil { return nil, nil } // Generate a response. We purposely omit the parent reference otherwise // you could escalade your privileges. resp := &logical.Response{ Data: map[string]interface{}{ "id": out.ID, "policies": out.Policies, "path": out.Path, "meta": out.Meta, "display_name": out.DisplayName, "num_uses": out.NumUses, }, } return resp, nil }
// DuoHandler interacts with the Duo Auth API to authenticate a user // login request. If successful, the original response from the login // backend is returned. func DuoHandler(req *logical.Request, d *framework.FieldData, resp *logical.Response) ( *logical.Response, error) { duoConfig, err := GetDuoConfig(req) if err != nil || duoConfig == nil { return logical.ErrorResponse("Could not load Duo configuration"), nil } duoAuthClient, err := GetDuoAuthClient(req, duoConfig) if err != nil { return logical.ErrorResponse(err.Error()), nil } username, ok := resp.Auth.Metadata["username"] if !ok { return logical.ErrorResponse("Could not read username for MFA"), nil } var request *duoAuthRequest = &duoAuthRequest{} request.successResp = resp request.username = username request.method = d.Get("method").(string) request.passcode = d.Get("passcode").(string) request.ipAddr = req.Connection.RemoteAddr return duoHandler(duoConfig, duoAuthClient, request) }
func pathEncryptWrite( req *logical.Request, d *framework.FieldData) (*logical.Response, error) { name := d.Get("name").(string) value := d.Get("plaintext").(string) if len(value) == 0 { return logical.ErrorResponse("missing plaintext to encrypt"), logical.ErrInvalidRequest } // Get the policy p, err := getPolicy(req, name) if err != nil { return nil, err } // Decode the context if any contextRaw := d.Get("context").(string) var context []byte if len(contextRaw) != 0 { var err error context, err = base64.StdEncoding.DecodeString(contextRaw) if err != nil { return logical.ErrorResponse("failed to decode context as base64"), logical.ErrInvalidRequest } } // Error if invalid policy if p == nil { isDerived := len(context) != 0 p, err = generatePolicy(req.Storage, name, isDerived) if err != nil { return logical.ErrorResponse(fmt.Sprintf("failed to upsert policy: %v", err)), logical.ErrInvalidRequest } } ciphertext, err := p.Encrypt(context, value) if err != nil { switch err.(type) { case certutil.UserError: return logical.ErrorResponse(err.Error()), logical.ErrInvalidRequest case certutil.InternalError: return nil, err default: return nil, err } } if ciphertext == "" { return nil, fmt.Errorf("empty ciphertext returned") } // Generate the response resp := &logical.Response{ Data: map[string]interface{}{ "ciphertext": ciphertext, }, } return resp, nil }
// used to intercept an HTTPCodedError so it goes back to callee func handleError( err error) (*logical.Response, error) { switch err.(type) { case logical.HTTPCodedError: return logical.ErrorResponse(err.Error()), err default: return logical.ErrorResponse(err.Error()), logical.ErrInvalidRequest } }
func (b *backend) pathRoleCreate( req *logical.Request, data *framework.FieldData) (*logical.Response, error) { name := data.Get("name").(string) if name == "" { return logical.ErrorResponse("Missing name"), nil } roleDB := data.Get("db").(string) if roleDB == "" { return logical.ErrorResponse("db parameter is required"), nil } // Example roles JSON: // // [ "readWrite", { "role": "readWrite", "db": "test" } ] // // For storage, we convert such an array into a homogeneous array of role documents like: // // [ { "role": "readWrite" }, { "role": "readWrite", "db": "test" } ] // var roles []mongodbRole rolesJson := []byte(data.Get("roles").(string)) if len(rolesJson) > 0 { var rolesArray []interface{} err := json.Unmarshal(rolesJson, &rolesArray) if err != nil { return nil, err } for _, rawRole := range rolesArray { switch role := rawRole.(type) { case string: roles = append(roles, mongodbRole{Role: role}) case map[string]interface{}: if db, ok := role["db"].(string); ok { if roleName, ok := role["role"].(string); ok { roles = append(roles, mongodbRole{Role: roleName, DB: db}) } } } } } // Store it entry, err := logical.StorageEntryJSON("role/"+name, &roleStorageEntry{ DB: roleDB, MongoDBRoles: roles, }) if err != nil { return nil, err } if err := req.Storage.Put(entry); err != nil { return nil, err } return nil, nil }
func (b *backend) pathLogin( req *logical.Request, data *framework.FieldData) (*logical.Response, error) { // Get the connection state if req.Connection == nil || req.Connection.ConnState == nil { return logical.ErrorResponse("tls connection required"), nil } connState := req.Connection.ConnState // Load the trusted certificates roots, trusted := b.loadTrustedCerts(req.Storage) // Validate the connection state is trusted trustedChains, err := validateConnState(roots, connState) if err != nil { return nil, err } // If no trusted chain was found, client is not authenticated if len(trustedChains) == 0 { return logical.ErrorResponse("invalid certificate or no client certificate supplied"), nil } validChain := b.checkForValidChain(req.Storage, trustedChains) if !validChain { return logical.ErrorResponse( "no chain containing non-revoked certificates could be found for this login certificate", ), nil } // Match the trusted chain with the policy matched := b.matchPolicy(trustedChains, trusted) if matched == nil { return nil, nil } ttl := matched.Entry.TTL if ttl == 0 { ttl = b.System().DefaultLeaseTTL() } // Generate a response resp := &logical.Response{ Auth: &logical.Auth{ Policies: matched.Entry.Policies, DisplayName: matched.Entry.DisplayName, Metadata: map[string]string{ "cert_name": matched.Entry.Name, "common_name": connState.PeerCertificates[0].Subject.CommonName, }, LeaseOptions: logical.LeaseOptions{ Renewable: true, TTL: ttl, }, }, } return resp, nil }