blob: 89b5cccbba1e1abeecdf9812e8bcfe1fe547eb38 [file] [log] [blame]
// Copyright 2015 The Vanadium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// The following enables go generate to generate the doc.go file.
//go:generate go run $JIRI_ROOT/release/go/src/v.io/x/lib/cmdline/testdata/gendoc.go . -help
package main
import (
"bytes"
"database/sql"
"encoding/base64"
"encoding/json"
"fmt"
"io/ioutil"
"os"
"v.io/v23"
"v.io/v23/context"
"v.io/v23/security"
"v.io/v23/vom"
"v.io/x/lib/cmdline"
"v.io/x/lib/dbutil"
vsecurity "v.io/x/ref/lib/security"
"v.io/x/ref/lib/v23cmd"
_ "v.io/x/ref/runtime/factories/roaming"
"v.io/x/ref/services/identity/internal/auditor"
"v.io/x/ref/services/identity/internal/caveats"
"v.io/x/ref/services/identity/internal/handlers"
"v.io/x/ref/services/identity/internal/oauth"
"v.io/x/ref/services/identity/internal/revocation"
"v.io/x/ref/services/identity/internal/server"
"v.io/x/ref/services/internal/restsigner"
)
var (
googleConfigWeb string
externalHttpAddr, httpAddr, tlsConfig, assetsPrefix, mountPrefix string
dischargerLocation string
remoteSignerBlessingsDir string
oauthRemoteSignerBlessingsDir string
sqlConf string
registeredAppConfig string
userBlessings, appBlessings string
)
func init() {
// Configuration for various Google OAuth-based clients.
cmdIdentityD.Flags.StringVar(&googleConfigWeb, "google-config-web", "", "Path to JSON-encoded OAuth client configuration for the web application that renders the audit log for blessings provided by this provider.")
// Configuration using the remote signer
cmdIdentityD.Flags.StringVar(&userBlessings, "user-blessings", "", "Path to a file containing base64url-vom encoded blessings that will be extended with the username of the requestor.")
cmdIdentityD.Flags.StringVar(&appBlessings, "app-blessings", "", "Path to a file containing base64url-vom encoded blessings that will be extended with an application identifier and the username of the requestor (i.e., a user using a specific app)")
cmdIdentityD.Flags.StringVar(&registeredAppConfig, "registered-apps", "", "Path to the config file for registered oauth clients.")
// Flags controlling the HTTP server
cmdIdentityD.Flags.StringVar(&externalHttpAddr, "external-http-addr", "", "External address on which the HTTP server listens on. If none is provided the server will only listen on -http-addr.")
cmdIdentityD.Flags.StringVar(&httpAddr, "http-addr", "localhost:8125", "Address on which the HTTP server listens on.")
cmdIdentityD.Flags.StringVar(&tlsConfig, "tls-config", "", "Comma-separated list of TLS certificate and private key files, in that order. This must be provided.")
cmdIdentityD.Flags.StringVar(&assetsPrefix, "assets-prefix", "", "Host serving the web assets for the identity server.")
cmdIdentityD.Flags.StringVar(&mountPrefix, "mount-prefix", "identity", "Mount name prefix to use. May be rooted.")
// Flag controlling auditing and revocation of Blessing operations
cmdIdentityD.Flags.StringVar(&sqlConf, "sql-config", "", "Path to configuration file for MySQL database connection. Database is used to persist blessings for auditing and revocation. "+dbutil.SqlConfigFileDescription)
cmdIdentityD.Flags.StringVar(&dischargerLocation, "discharger-location", "", "The name of the discharger service. May be rooted. If empty, the published name is used.")
}
func main() {
cmdline.HideGlobalFlagsExcept()
cmdline.Main(cmdIdentityD)
}
var cmdIdentityD = &cmdline.Command{
Runner: v23cmd.RunnerFunc(runIdentityD),
Name: "identityd",
Short: "Runs HTTP server that creates security.Blessings objects",
Long: `
Command identityd runs a daemon HTTP server that uses OAuth to create
security.Blessings objects.
Starts an HTTP server that brokers blessings after authenticating through OAuth.
To generate TLS certificates so the HTTP server can use SSL:
go run $(go list -f {{.Dir}} "crypto/tls")/generate_cert.go --host <IP address>
To use Google as an OAuth provider the -google-config-web flag must be set to
point to the a JSON file obtained after registering the application with the
Google Developer Console at https://cloud.google.com/console
More details on Google OAuth at:
https://developers.google.com/accounts/docs/OAuth2Login
More details on the design of identityd at:
https://vanadium.github.io/designdocs/identity-service.html
`,
}
func runIdentityD(ctx *context.T, env *cmdline.Env, args []string) error {
var sqlDB *sql.DB
var err error
if sqlConf != "" {
if sqlDB, err = dbutil.NewSqlDBConnFromFile(sqlConf, "SERIALIZABLE"); err != nil {
return env.UsageErrorf("Failed to create sqlDB: %v", err)
}
}
if ctx, err = initRemoteSigner(ctx, userBlessings); err != nil {
return err
}
oauthCtx, err := initRemoteSigner(ctx, appBlessings)
if err != nil {
return err
}
registeredApps, err := readRegisteredAppsConfig()
if err != nil {
return err
}
googleoauth, err := oauth.NewGoogleOAuth(ctx, googleConfigWeb)
if err != nil {
return env.UsageErrorf("Failed to setup GoogleOAuth: %v", err)
}
auditor, reader, err := auditor.NewSQLBlessingAuditor(ctx, sqlDB)
if err != nil {
return fmt.Errorf("Failed to create sql auditor from config: %v", err)
}
revocationManager, err := revocation.NewRevocationManager(ctx, sqlDB)
if err != nil {
return fmt.Errorf("Failed to start RevocationManager: %v", err)
}
s := server.NewIdentityServer(
googleoauth,
auditor,
reader,
revocationManager,
caveats.NewBrowserCaveatSelector(assetsPrefix),
assetsPrefix,
mountPrefix,
dischargerLocation,
registeredApps)
s.Serve(ctx, oauthCtx, externalHttpAddr, httpAddr, tlsConfig)
return nil
}
func initRemoteSigner(ctx *context.T, blessings string) (*context.T, error) {
if len(blessings) == 0 {
return ctx, nil
}
signer, err := restsigner.NewRestSigner()
if err != nil {
return nil, err
}
// Decode the blessings and ensure that they are attached to the same public key.
encoded, err := ioutil.ReadFile(blessings)
if err != nil {
return nil, err
}
buf := bytes.NewBuffer(encoded)
var b security.Blessings
if err := vom.NewDecoder(base64.NewDecoder(base64.URLEncoding, buf)).Decode(&b); err != nil {
return nil, err
}
if buf.Len() != 0 {
return nil, fmt.Errorf("unexpected trailing %d bytes in %s", buf.Len(), blessings)
}
p, err := security.CreatePrincipal(signer, vsecurity.FixedBlessingsStore(b, nil), vsecurity.NewBlessingRoots())
if err != nil {
return nil, err
}
if err := security.AddToRoots(p, b); err != nil {
return nil, err
}
return v23.WithPrincipal(ctx, p)
}
func readRegisteredAppsConfig() (registeredApps handlers.RegisteredAppMap, err error) {
if registeredAppConfig == "" {
return nil, nil
}
var configFile *os.File
configFile, err = os.Open(registeredAppConfig)
if err != nil {
return nil, fmt.Errorf("Failed to open registered app config: %v", err)
}
defer configFile.Close()
dec := json.NewDecoder(configFile)
if err = dec.Decode(&registeredApps); err != nil {
return nil, fmt.Errorf("Error parsing registered apps: %v", err)
}
return registeredApps, nil
}