| // 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(®isteredAppConfig, "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(®isteredApps); err != nil { |
| return nil, fmt.Errorf("Error parsing registered apps: %v", err) |
| |
| } |
| return registeredApps, nil |
| } |