blob: 4ef1f5e94a5f03ae706d3445c6c8a24bed342670 [file] [log] [blame]
Asim Shankar220a0152014-10-30 21:21:09 -07001// HTTP server that uses OAuth to create security.Blessings objects.
Suharsh Sivakumar91bc52e2015-02-06 10:59:50 -08002// For more information on our setup of the identity server see:
3// https://docs.google.com/document/d/1ebQ1sQn95cFu8yQM36rpJ8mQvsU29aa1o03ADhi52BM
Jiri Simsa5293dcb2014-05-10 09:56:38 -07004package main
5
6import (
Suharsh Sivakumar38a1a7b2014-11-17 15:14:38 -08007 "database/sql"
Jiri Simsa5293dcb2014-05-10 09:56:38 -07008 "flag"
9 "fmt"
Jiri Simsa5293dcb2014-05-10 09:56:38 -070010 "os"
Asim Shankar71061572014-07-22 16:59:18 -070011 "time"
Jiri Simsa5293dcb2014-05-10 09:56:38 -070012
Suharsh Sivakumar19fbf992015-01-23 11:02:27 -080013 "v.io/core/veyron2"
Jiri Simsa764efb72014-12-25 20:57:03 -080014 "v.io/core/veyron2/vlog"
Cosmos Nicolaoud6c3c9c2014-09-30 15:42:53 -070015
Suharsh Sivakumar19fbf992015-01-23 11:02:27 -080016 _ "v.io/core/veyron/profiles/static"
Jiri Simsa764efb72014-12-25 20:57:03 -080017 "v.io/core/veyron/services/identity/auditor"
18 "v.io/core/veyron/services/identity/blesser"
19 "v.io/core/veyron/services/identity/caveats"
20 "v.io/core/veyron/services/identity/oauth"
21 "v.io/core/veyron/services/identity/revocation"
22 "v.io/core/veyron/services/identity/server"
Asim Shankarc195b6d2015-02-03 11:26:55 -080023 "v.io/core/veyron/services/identity/util"
Jiri Simsa5293dcb2014-05-10 09:56:38 -070024)
25
26var (
Asim Shankar7a721752014-08-02 14:27:23 -070027 // Configuration for various Google OAuth-based clients.
Suharsh Sivakumard308c7e2014-10-03 12:46:50 -070028 googleConfigWeb = flag.String("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.")
29 googleConfigChrome = flag.String("google_config_chrome", "", "Path to the JSON-encoded OAuth client configuration for Chrome browser applications that obtain blessings from this server (via the OAuthBlesser.BlessUsingAccessToken RPC) from this server.")
30 googleConfigAndroid = flag.String("google_config_android", "", "Path to the JSON-encoded OAuth client configuration for Android applications that obtain blessings from this server (via the OAuthBlesser.BlessUsingAccessToken RPC) from this server.")
Asim Shankarc195b6d2015-02-03 11:26:55 -080031 emailClassifier util.EmailClassifier
Nicolas LaCasse1b0c8ba2015-01-07 17:49:25 -080032
33 // Flags controlling the HTTP server
34 host = flag.String("host", defaultHost(), "Hostname the HTTP server listens on. This can be the name of the host running the webserver, but if running behind a NAT or load balancer, this should be the host name that clients will connect to. For example, if set to 'x.com', Veyron identities will have the IssuerName set to 'x.com' and clients can expect to find the root name and public key of the signer at 'x.com/blessing-root'.")
35 httpaddr = flag.String("httpaddr", "localhost:8125", "Address on which the HTTP server listens on.")
Nicolas LaCasse098a9852015-01-08 13:41:45 -080036 tlsconfig = flag.String("tlsconfig", "", "Comma-separated list of TLS certificate and private key files, in that order. This must be provided.")
Jiri Simsa5293dcb2014-05-10 09:56:38 -070037)
38
39func main() {
Asim Shankarc195b6d2015-02-03 11:26:55 -080040 flag.Var(&emailClassifier, "email_classifier", "A comma-separated list of <domain>=<prefix> pairs. For example 'google.com=internal,v.io=trusted'. When specified, then the blessings generated for email address of <domain> will use the extension <prefix>/<email> instead of the default extension of users/<email>.")
Jiri Simsa5293dcb2014-05-10 09:56:38 -070041 flag.Usage = usage
Suharsh Sivakumar38a1a7b2014-11-17 15:14:38 -080042 flag.Parse()
43
44 var sqlDB *sql.DB
45 var err error
Suharsh Sivakumar91bc52e2015-02-06 10:59:50 -080046 if len(*sqlConf) > 0 {
47 if sqlDB, err = dbFromConfigFile(*sqlConf); err != nil {
Suharsh Sivakumar38a1a7b2014-11-17 15:14:38 -080048 vlog.Fatalf("failed to create sqlDB: %v", err)
49 }
50 }
51
Asim Shankarc195b6d2015-02-03 11:26:55 -080052 googleoauth, err := oauth.NewGoogleOAuth(*googleConfigWeb)
Matt Rosencrantz110cf222014-12-01 16:08:54 -080053 if err != nil {
Suharsh Sivakumar8e898db2014-12-17 14:07:21 -080054 vlog.Fatalf("Failed to setup GoogleOAuth: %v", err)
Suharsh Sivakumarfb5cbb72014-08-27 13:14:22 -070055 }
56
Suharsh Sivakumar8e898db2014-12-17 14:07:21 -080057 auditor, reader, err := auditor.NewSQLBlessingAuditor(sqlDB)
Asim Shankar7a721752014-08-02 14:27:23 -070058 if err != nil {
Suharsh Sivakumar8e898db2014-12-17 14:07:21 -080059 vlog.Fatalf("Failed to create sql auditor from config: %v", err)
Asim Shankar7a721752014-08-02 14:27:23 -070060 }
Jiri Simsa5293dcb2014-05-10 09:56:38 -070061
Suharsh Sivakumar8e898db2014-12-17 14:07:21 -080062 revocationManager, err := revocation.NewRevocationManager(sqlDB)
Asim Shankar61071792014-07-22 13:03:18 -070063 if err != nil {
Suharsh Sivakumar8e898db2014-12-17 14:07:21 -080064 vlog.Fatalf("Failed to start RevocationManager: %v", err)
Asim Shankar61071792014-07-22 13:03:18 -070065 }
Suharsh Sivakumard308c7e2014-10-03 12:46:50 -070066
Suharsh Sivakumar19fbf992015-01-23 11:02:27 -080067 ctx, shutdown := veyron2.Init()
68 defer shutdown()
Matt Rosencrantzf1c3b442015-01-12 17:53:08 -080069
Suharsh Sivakumar19fbf992015-01-23 11:02:27 -080070 listenSpec := veyron2.GetListenSpec(ctx)
Nicolas LaCasse1b0c8ba2015-01-07 17:49:25 -080071 s := server.NewIdentityServer(
Suharsh Sivakumara76dba62014-12-22 16:00:34 -080072 googleoauth,
73 auditor,
74 reader,
75 revocationManager,
Ankur123a5c72015-01-12 16:03:43 -080076 googleOAuthBlesserParams(googleoauth, revocationManager),
Asim Shankarc195b6d2015-02-03 11:26:55 -080077 caveats.NewBrowserCaveatSelector(),
78 &emailClassifier)
Suharsh Sivakumar19fbf992015-01-23 11:02:27 -080079 s.Serve(ctx, &listenSpec, *host, *httpaddr, *tlsconfig)
Jiri Simsa5293dcb2014-05-10 09:56:38 -070080}
81
82func usage() {
Asim Shankarb18a44f2014-10-21 20:25:07 -070083 fmt.Fprintf(os.Stderr, `%s starts an HTTP server that brokers blessings after authenticating through OAuth.
Jiri Simsa5293dcb2014-05-10 09:56:38 -070084
85To generate TLS certificates so the HTTP server can use SSL:
Nicolas LaCasse1b0c8ba2015-01-07 17:49:25 -080086go run $(go list -f {{.Dir}} "crypto/tls")/generate_cert.go --host <IP address>
Jiri Simsa5293dcb2014-05-10 09:56:38 -070087
Asim Shankarb18a44f2014-10-21 20:25:07 -070088To use Google as an OAuth provider the --google_config_* flags must be set to point to
89the a JSON file obtained after registering the application with the Google Developer Console
90at https://cloud.google.com/console
Asim Shankar1c3b1812014-07-31 18:54:51 -070091
Jiri Simsa5293dcb2014-05-10 09:56:38 -070092More details on Google OAuth at:
93https://developers.google.com/accounts/docs/OAuth2Login
94
95Flags:
96`, os.Args[0])
97 flag.PrintDefaults()
98}
99
Ankur123a5c72015-01-12 16:03:43 -0800100func googleOAuthBlesserParams(oauthProvider oauth.OAuthProvider, revocationManager revocation.RevocationManager) blesser.OAuthBlesserParams {
101 params := blesser.OAuthBlesserParams{
102 OAuthProvider: oauthProvider,
Suharsh Sivakumar8e898db2014-12-17 14:07:21 -0800103 BlessingDuration: 365 * 24 * time.Hour,
Asim Shankarc195b6d2015-02-03 11:26:55 -0800104 EmailClassifier: &emailClassifier,
Suharsh Sivakumar8e898db2014-12-17 14:07:21 -0800105 RevocationManager: revocationManager,
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700106 }
Suharsh Sivakumar8e898db2014-12-17 14:07:21 -0800107 if clientID, err := getOAuthClientID(*googleConfigChrome); err != nil {
108 vlog.Info(err)
109 } else {
Ankur123a5c72015-01-12 16:03:43 -0800110 params.AccessTokenClients = append(params.AccessTokenClients, oauth.AccessTokenClient{Name: "chrome", ClientID: clientID})
Asim Shankarb18a44f2014-10-21 20:25:07 -0700111 }
Suharsh Sivakumar8e898db2014-12-17 14:07:21 -0800112 if clientID, err := getOAuthClientID(*googleConfigAndroid); err != nil {
113 vlog.Info(err)
114 } else {
Ankur123a5c72015-01-12 16:03:43 -0800115 params.AccessTokenClients = append(params.AccessTokenClients, oauth.AccessTokenClient{Name: "android", ClientID: clientID})
Asim Shankarb18a44f2014-10-21 20:25:07 -0700116 }
Ankur123a5c72015-01-12 16:03:43 -0800117 return params
Suharsh Sivakumar305626a2014-11-10 09:50:24 -0800118}
119
Suharsh Sivakumar8e898db2014-12-17 14:07:21 -0800120func getOAuthClientID(configFile string) (clientID string, err error) {
121 f, err := os.Open(configFile)
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700122 if err != nil {
Suharsh Sivakumar8e898db2014-12-17 14:07:21 -0800123 return "", fmt.Errorf("failed to open %q: %v", configFile, err)
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700124 }
Suharsh Sivakumar8e898db2014-12-17 14:07:21 -0800125 defer f.Close()
126 clientID, err = oauth.ClientIDFromJSON(f)
127 if err != nil {
128 return "", fmt.Errorf("failed to decode JSON in %q: %v", configFile, err)
129 }
130 return clientID, nil
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700131}
Nicolas LaCasse1b0c8ba2015-01-07 17:49:25 -0800132
133func defaultHost() string {
134 host, err := os.Hostname()
135 if err != nil {
136 vlog.Fatalf("os.Hostname() failed: %v", err)
137 }
138 return host
139}