1
0
mirror of https://github.com/docker/docker-credential-helpers.git synced 2026-06-13 16:01:28 +05:30

secretservice: add D-Bus secret service

Signed-off-by: Antonio Murdaca <runcom@redhat.com>
This commit is contained in:
Antonio Murdaca
2016-03-02 16:38:17 +01:00
parent 900f815cd4
commit a96948acb3
10 changed files with 295 additions and 13 deletions
+13 -4
View File
@@ -1,19 +1,28 @@
--- ---
# See appveyor.yml for windows build. # See appveyor.yml for windows build.
sudo: false sudo: required
language: go language: go
dist: trusty
os: os:
- linux
- osx - osx
notifications: notifications:
email: false email: false
go: go:
- 1.6 - 1.6
install: make deps install: make deps
before_script: make validate addons:
apt:
packages:
- libsecret-1-dev
before_script:
- "export DISPLAY=:99.0"
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then sh ci/before_script_linux.sh; fi
- make validate
script: make test script: make test
before_deploy: before_deploy:
- sh ci/before_deploy.sh - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then sh ci/before_deploy_osx.sh; fi
deploy: deploy:
provider: releases provider: releases
@@ -25,7 +34,7 @@
# deploy when a new tag is pushed # deploy when a new tag is pushed
on: on:
tags: true tags: true
branches: branches:
only: only:
# Pushes and PR to the master branch # Pushes and PR to the master branch
+25 -9
View File
@@ -1,4 +1,6 @@
.PHONY: all deps osxkeychain test validate wincred .PHONY: all deps osxkeychain secretservice test validate wincred
TRAVIS_OS_NAME ?= linux
all: test all: test
@@ -9,15 +11,29 @@ osxkeychain:
mkdir -p bin mkdir -p bin
go build -o bin/docker-credential-osxkeychain osxkeychain/cmd/main_darwin.go go build -o bin/docker-credential-osxkeychain osxkeychain/cmd/main_darwin.go
test: secretservice:
# tests all packages except vendor mkdir -p bin
go test -v `go list ./... | grep -v /vendor/` go build -o bin/docker-credential-secretservice secretservice/cmd/main_linux.go
validate:
go vet ./credentials ./osxkeychain
golint `go list ./... | grep -v /vendor/`
gofmt -s -l `ls **/*.go | grep -v vendor`
wincred: wincred:
mkdir -p bin mkdir -p bin
go build -o bin/docker-credential-wincred wincred/cmd/main_windows.go go build -o bin/docker-credential-wincred wincred/cmd/main_windows.go
test:
# tests all packages except vendor
go test -v `go list ./... | grep -v /vendor/`
vet: vet_$(TRAVIS_OS_NAME)
go vet ./credentials
vet_osx:
go vet ./osxkeychain
vet_linux:
go vet ./secretservice
validate: vet
for p in `go list ./... | grep -v /vendor/`; do \
golint $$p ; \
done
gofmt -s -l `ls **/*.go | grep -v vendor`
+1
View File
@@ -38,6 +38,7 @@ Set the `credsStore` option in your `.docker/config.json` file with the suffix o
### Available programs ### Available programs
1. osxkeychain: Provides a helper to use the OS X keychain as credentials store. 1. osxkeychain: Provides a helper to use the OS X keychain as credentials store.
1. secretservice: Provides a helper to use the D-Bus secret service as credentials store.
2. wincred: Provides a helper to use Windows credentials manager as store. 2. wincred: Provides a helper to use Windows credentials manager as store.
## Development ## Development
+4
View File
@@ -0,0 +1,4 @@
set -ex
sh -e /etc/init.d/xvfb start
sleep 3 # give xvfb some time to start
+10
View File
@@ -0,0 +1,10 @@
package main
import (
"github.com/docker/docker-credential-helpers/credentials"
"github.com/docker/docker-credential-helpers/secretservice"
)
func main() {
credentials.Serve(secretservice.New())
}
+98
View File
@@ -0,0 +1,98 @@
#include <string.h>
#include "secretservice_linux.h"
const SecretSchema *docker_get_schema(void)
{
static const SecretSchema docker_schema = {
"io.docker.Credentials", SECRET_SCHEMA_NONE,
{
{ "server", SECRET_SCHEMA_ATTRIBUTE_STRING },
{ "username", SECRET_SCHEMA_ATTRIBUTE_STRING },
{ "docker_cli", SECRET_SCHEMA_ATTRIBUTE_STRING },
{ "NULL", 0 },
}
};
return &docker_schema;
}
GError *add(char *server, char *username, char *password) {
GError *err = NULL;
secret_password_store_sync (DOCKER_SCHEMA, SECRET_COLLECTION_DEFAULT,
server, password, NULL, &err,
"server", server,
"username", username,
"docker_cli", "1",
NULL);
return err;
}
GError *delete(char *server) {
GError *err = NULL;
secret_password_clear_sync(DOCKER_SCHEMA, NULL, &err,
"server", server,
"docker_cli", "1",
NULL);
if (err != NULL)
return err;
return NULL;
}
char *get_username(SecretItem *item) {
GHashTable *attributes;
GHashTableIter iter;
gchar *value, *key;
attributes = secret_item_get_attributes(item);
g_hash_table_iter_init(&iter, attributes);
while (g_hash_table_iter_next(&iter, (void **)&key, (void **)&value)) {
if (strncmp(key, "username", strlen(key)) == 0)
return (char *)value;
}
g_hash_table_unref(attributes);
return NULL;
}
GError *get(char *server, char **username, char **password) {
GError *err = NULL;
GHashTable *attributes;
SecretService *service;
GList *items, *l;
SecretSearchFlags flags = SECRET_SEARCH_LOAD_SECRETS | SECRET_SEARCH_ALL | SECRET_SEARCH_UNLOCK;
SecretValue *secret;
gsize length;
gchar *value;
attributes = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
g_hash_table_insert(attributes, g_strdup("server"), g_strdup(server));
g_hash_table_insert(attributes, g_strdup("docker_cli"), g_strdup("1"));
service = secret_service_get_sync(SECRET_SERVICE_NONE, NULL, &err);
if (err == NULL) {
items = secret_service_search_sync(service, NULL, attributes, flags, NULL, &err);
if (err == NULL) {
for (l = items; l != NULL; l = g_list_next(l)) {
value = secret_item_get_schema_name(l->data);
if (strncmp(value, "io.docker.Credentials", strlen(value)) != 0) {
g_free(value);
continue;
}
g_free(value);
secret = secret_item_get_secret(l->data);
if (secret != NULL) {
*password = strdup(secret_value_get(secret, &length));
secret_value_unref(secret);
}
*username = get_username(l->data);
}
g_list_free_full(items, g_object_unref);
}
g_object_unref(service);
}
g_hash_table_unref(attributes);
if (err != NULL) {
return err;
}
return NULL;
}
+84
View File
@@ -0,0 +1,84 @@
package secretservice
/*
#cgo pkg-config: libsecret-1
#include "secretservice_linux.h"
#include <stdlib.h>
*/
import "C"
import (
"errors"
"unsafe"
"github.com/docker/docker-credential-helpers/credentials"
)
type secretservice struct{}
// New creates a new secretservice.
func New() credentials.Helper {
return secretservice{}
}
// Add adds new credentials to the keychain.
func (h secretservice) Add(creds *credentials.Credentials) error {
if creds == nil {
return errors.New("missing credentials")
}
server := C.CString(creds.ServerURL)
defer C.free(unsafe.Pointer(server))
username := C.CString(creds.Username)
defer C.free(unsafe.Pointer(username))
password := C.CString(creds.Password)
defer C.free(unsafe.Pointer(password))
if err := C.add(server, username, password); err != nil {
defer C.g_error_free(err)
errMsg := (*C.char)(unsafe.Pointer(err.message))
return errors.New(C.GoString(errMsg))
}
return nil
}
// Delete removes credentials from the keychain.
func (h secretservice) Delete(serverURL string) error {
if serverURL == "" {
return errors.New("missing server url")
}
server := C.CString(serverURL)
defer C.free(unsafe.Pointer(server))
if err := C.delete(server); err != nil {
defer C.g_error_free(err)
errMsg := (*C.char)(unsafe.Pointer(err.message))
return errors.New(C.GoString(errMsg))
}
return nil
}
// Get returns the username and password to use for a given registry server URL.
func (h secretservice) Get(serverURL string) (string, string, error) {
if serverURL == "" {
return "", "", errors.New("missing server url")
}
var username *C.char
defer C.free(unsafe.Pointer(username))
var password *C.char
defer C.free(unsafe.Pointer(password))
server := C.CString(serverURL)
defer C.free(unsafe.Pointer(server))
err := C.get(server, &username, &password)
if err != nil {
defer C.g_error_free(err)
errMsg := (*C.char)(unsafe.Pointer(err.message))
return "", "", errors.New(C.GoString(errMsg))
}
user := C.GoString(username)
pass := C.GoString(password)
if pass == "" {
return "", "", credentials.ErrCredentialsNotFound
}
return user, pass, nil
}
+11
View File
@@ -0,0 +1,11 @@
#define SECRET_WITH_UNSTABLE 1
#define SECRET_API_SUBJECT_TO_CHANGE 1
#include <libsecret/secret.h>
const SecretSchema *docker_get_schema(void) G_GNUC_CONST;
#define DOCKER_SCHEMA docker_get_schema()
GError *add(char *server, char *username, char *password);
GError *delete(char *server);
GError *get(char *server, char **username, char **password);
+49
View File
@@ -0,0 +1,49 @@
package secretservice
import (
"testing"
"github.com/docker/docker-credential-helpers/credentials"
)
func TestSecretServiceHelper(t *testing.T) {
t.Skip("test requires gnome-keyring but travis CI doesn't have it")
creds := &credentials.Credentials{
ServerURL: "https://foobar.docker.io:2376/v1",
Username: "foobar",
Password: "foobarbaz",
}
helper := New()
if err := helper.Add(creds); err != nil {
t.Fatal(err)
}
username, password, err := helper.Get(creds.ServerURL)
if err != nil {
t.Fatal(err)
}
if username != "foobar" {
t.Fatalf("expected %s, got %s\n", "foobar", username)
}
if password != "foobarbaz" {
t.Fatalf("expected %s, got %s\n", "foobarbaz", password)
}
if err := helper.Delete(creds.ServerURL); err != nil {
t.Fatal(err)
}
}
func TestMissingCredentials(t *testing.T) {
t.Skip("test requires gnome-keyring but travis CI doesn't have it")
helper := New()
_, _, err := helper.Get("https://adsfasdf.wrewerwer.com/asdfsdddd")
if err != credentials.ErrCredentialsNotFound {
t.Fatalf("exptected ErrCredentialsNotFound, got %v", err)
}
}