// HTTP server that uses OAuth to create security.Blessings objects.
package main

import (
	"crypto/rand"
	"database/sql"
	"flag"
	"fmt"
	_ "github.com/go-sql-driver/mysql"
	"html/template"
	"io/ioutil"
	"net"
	"net/http"
	"os"
	"strings"
	"time"

	"veyron.io/veyron/veyron2"
	"veyron.io/veyron/veyron2/ipc"
	"veyron.io/veyron/veyron2/naming"
	"veyron.io/veyron/veyron2/options"
	"veyron.io/veyron/veyron2/rt"
	"veyron.io/veyron/veyron2/security"
	verror "veyron.io/veyron/veyron2/verror2"
	"veyron.io/veyron/veyron2/vlog"

	"veyron.io/veyron/veyron/lib/signals"
	"veyron.io/veyron/veyron/security/audit"
	"veyron.io/veyron/veyron/services/identity/auditor"
	"veyron.io/veyron/veyron/services/identity/blesser"
	"veyron.io/veyron/veyron/services/identity/googleoauth"
	"veyron.io/veyron/veyron/services/identity/handlers"
	"veyron.io/veyron/veyron/services/identity/revocation"
	services "veyron.io/veyron/veyron/services/security"
	"veyron.io/veyron/veyron/services/security/discharger"

	"veyron.io/veyron/veyron/profiles/static"
)

var (
	// Flags controlling the HTTP server
	httpaddr  = flag.String("httpaddr", "localhost:8125", "Address on which the HTTP server listens on.")
	tlsconfig = flag.String("tlsconfig", "", "Comma-separated list of TLS certificate and private key files. This must be provided.")
	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 public key of the signer at 'x.com/pubkey/'.")

	// Flag controlling auditing and revocation of Blessing operations.
	sqlConfig = flag.String("sqlconfig", "", "Path to file containing go-sql-driver connection string of the following form: [username[:password]@][protocol[(address)]]/dbname")

	// Configuration for various Google OAuth-based clients.
	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.")
	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.")
	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.")
	googleDomain        = flag.String("google_domain", "", "An optional domain name. When set, only email addresses from this domain are allowed to authenticate via Google OAuth")
)

const (
	googleService     = "google"
	macaroonService   = "macaroon"
	dischargerService = "discharger"
)

func main() {
	flag.Usage = usage
	flag.Parse()

	var sqlDB *sql.DB
	var err error
	if len(*sqlConfig) > 0 {
		config, err := ioutil.ReadFile(*sqlConfig)
		if err != nil {
			vlog.Fatalf("failed to read sql config from %v", *sqlConfig)
		}
		sqlDB, err = dbFromConfigDatabase(strings.Trim(string(config), "\n"))
		if err != nil {
			vlog.Fatalf("failed to create sqlDB: %v", err)
		}
	}

	p, blessingLogReader := providerPrincipal(sqlDB)
	runtime, err := rt.New(options.RuntimePrincipal{p})
	if err != nil {
		vlog.Fatal(err)
	}
	defer runtime.Cleanup()

	var revocationManager *revocation.RevocationManager
	// Only set revocationManager sqlConfig (and thus sqlDB) is set.
	if sqlDB != nil {
		revocationManager, err = revocation.NewRevocationManager(sqlDB)
		if err != nil {
			vlog.Fatalf("Failed to start RevocationManager: %v", err)
		}
	}

	// Setup handlers
	http.Handle("/pubkey/", handlers.PublicKey{runtime.Principal().PublicKey()}) // public key of this server
	macaroonKey := make([]byte, 32)
	if _, err := rand.Read(macaroonKey); err != nil {
		vlog.Fatalf("macaroonKey generation failed: %v", err)
	}
	// Google OAuth
	ipcServer, published, err := setupServices(runtime, revocationManager, macaroonKey)
	if err != nil {
		vlog.Fatalf("Failed to setup veyron services for blessing: %v", err)
	}
	defer ipcServer.Stop()
	if clientID, clientSecret, ok := getOAuthClientIDAndSecret(*googleConfigWeb); ok {
		n := "/google/"
		h, err := googleoauth.NewHandler(googleoauth.HandlerArgs{
			R:                       runtime,
			MacaroonKey:             macaroonKey,
			Addr:                    fmt.Sprintf("%s%s", httpaddress(), n),
			ClientID:                clientID,
			ClientSecret:            clientSecret,
			BlessingLogReader:       blessingLogReader,
			RevocationManager:       revocationManager,
			MacaroonBlessingService: naming.JoinAddressName(published[0], macaroonService),
		})
		if err != nil {
			vlog.Fatalf("Failed to create HTTP handler for google-based authentication: %v", err)
		}
		http.Handle(n, h)
	}
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		args := struct {
			Self                            security.Blessings
			RandomWeb                       bool
			GoogleServers, DischargeServers []string
			ListBlessingsRoute              string
		}{
			Self:      runtime.Principal().BlessingStore().Default(),
			RandomWeb: enableRandomHandler(),
		}
		if revocationManager != nil {
			args.DischargeServers = appendSuffixTo(published, dischargerService)
		}
		if len(*googleConfigChrome) > 0 || len(*googleConfigAndroid) > 0 {
			args.GoogleServers = appendSuffixTo(published, googleService)
		}
		if sqlDB != nil && len(*googleConfigWeb) > 0 {
			args.ListBlessingsRoute = googleoauth.ListBlessingsRoute
		}
		if err := tmpl.Execute(w, args); err != nil {
			vlog.Info("Failed to render template:", err)
		}
	})
	vlog.Infof("Running HTTP server at: %v", httpaddress())
	go runHTTPSServer(*httpaddr)
	<-signals.ShutdownOnSignals(runtime)
}

func appendSuffixTo(objectname []string, suffix string) []string {
	names := make([]string, len(objectname))
	for i, o := range objectname {
		names[i] = naming.JoinAddressName(o, suffix)
	}
	return names
}

// newDispatcher returns a dispatcher for both the blessing and the
// discharging service.
func newDispatcher(googleParams blesser.GoogleParams, macaroonKey []byte) ipc.Dispatcher {
	d := dispatcher(map[string]interface{}{
		macaroonService:   blesser.NewMacaroonBlesserServer(macaroonKey),
		dischargerService: services.DischargerServer(discharger.NewDischarger()),
	})
	if len(*googleConfigChrome) > 0 || len(*googleConfigAndroid) > 0 {
		d[googleService] = blesser.NewGoogleOAuthBlesserServer(googleParams)
	}
	return d
}

type allowEveryoneAuthorizer struct{}

func (allowEveryoneAuthorizer) Authorize(security.Context) error { return nil }

type dispatcher map[string]interface{}

func (d dispatcher) Lookup(suffix string) (interface{}, security.Authorizer, error) {
	if invoker := d[suffix]; invoker != nil {
		return invoker, allowEveryoneAuthorizer{}, nil
	}
	return nil, nil, verror.Make(verror.NoExist, nil, suffix)
}

// Starts the blessing services and the discharging service on the same port.
func setupServices(r veyron2.Runtime, revocationManager *revocation.RevocationManager, macaroonKey []byte) (ipc.Server, []string, error) {
	googleParams := blesser.GoogleParams{
		// TODO(ashankar,nlacasse): Figure out how to have web-appications use the "caveats" form and
		// always select an expiry instead of forcing a ridiculously large value here.
		BlessingDuration:  365 * 24 * time.Hour,
		DomainRestriction: *googleDomain,
		RevocationManager: revocationManager,
	}
	if clientID, ok := getOAuthClientID(*googleConfigChrome); ok {
		googleParams.AccessTokenClients = append(googleParams.AccessTokenClients, blesser.AccessTokenClient{Name: "chrome", ClientID: clientID})
	}
	if clientID, ok := getOAuthClientID(*googleConfigAndroid); ok {
		googleParams.AccessTokenClients = append(googleParams.AccessTokenClients, blesser.AccessTokenClient{Name: "android", ClientID: clientID})
	}
	server, err := r.NewServer()
	if err != nil {
		return nil, nil, fmt.Errorf("failed to create new ipc.Server: %v", err)
	}
	ep, err := server.Listen(static.ListenSpec)
	if err != nil {
		return nil, nil, fmt.Errorf("server.Listen(%v) failed: %v", static.ListenSpec, err)
	}
	googleParams.DischargerLocation = naming.JoinAddressName(ep.String(), dischargerService)

	dispatcher := newDispatcher(googleParams, macaroonKey)
	objectname := naming.Join("identity", fmt.Sprintf("%v", r.Principal().BlessingStore().Default()))
	if err := server.ServeDispatcher(objectname, dispatcher); err != nil {
		return nil, nil, fmt.Errorf("failed to start Veyron services: %v", err)
	}
	vlog.Infof("Google blessing and discharger services enabled at %v", naming.JoinAddressName(ep.String(), objectname))
	published, _ := server.Published()
	if len(published) == 0 {
		// No addresses published, publish the endpoint instead (which may not be usable everywhere, but oh-well).
		published = append(published, ep.String())
	}
	return server, published, nil
}

func enableRandomHandler() bool {
	return len(*googleConfigWeb)+len(*googleConfigChrome)+len(*googleConfigAndroid) == 0
}
func getOAuthClientID(config string) (clientID string, ok bool) {
	fname := config
	if len(fname) == 0 {
		return "", false
	}
	f, err := os.Open(fname)
	if err != nil {
		vlog.Fatalf("Failed to open %q: %v", fname, err)
	}
	defer f.Close()
	clientID, err = googleoauth.ClientIDFromJSON(f)
	if err != nil {
		vlog.Fatalf("Failed to decode JSON in %q: %v", fname, err)
	}
	return clientID, true
}
func getOAuthClientIDAndSecret(config string) (clientID, clientSecret string, ok bool) {
	fname := config
	if len(fname) == 0 {
		return "", "", false
	}
	f, err := os.Open(fname)
	if err != nil {
		vlog.Fatalf("Failed to open %q: %v", fname, err)
	}
	defer f.Close()
	clientID, clientSecret, err = googleoauth.ClientIDAndSecretFromJSON(f)
	if err != nil {
		vlog.Fatalf("Failed to decode JSON in %q: %v", fname, err)
	}
	return clientID, clientSecret, true
}
func runHTTPSServer(addr string) {
	if len(*tlsconfig) == 0 {
		vlog.Fatal("Please set the --tlsconfig flag")
	}
	paths := strings.Split(*tlsconfig, ",")
	if len(paths) != 2 {
		vlog.Fatalf("Could not parse --tlsconfig. Must have exactly two components, separated by a comma")
	}
	vlog.Infof("Starting HTTP server with TLS using certificate [%s] and private key [%s] at https://%s", paths[0], paths[1], addr)
	if err := http.ListenAndServeTLS(addr, paths[0], paths[1], nil); err != nil {
		vlog.Fatalf("http.ListenAndServeTLS failed: %v", err)
	}
}

func usage() {
	fmt.Fprintf(os.Stderr, `%s starts an HTTP server that brokers blessings after authenticating through OAuth.

To generate TLS certificates so the HTTP server can use SSL:
go run $GOROOT/src/pkg/crypto/tls/generate_cert.go --host <IP address>

To use Google as an OAuth provider the --google_config_* flags 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

Flags:
`, os.Args[0])
	flag.PrintDefaults()
}

func defaultHost() string {
	host, err := os.Hostname()
	if err != nil {
		vlog.Fatalf("Failed to get hostname: %v", err)
	}
	return host
}

// providerPrincipal returns the Principal to use for the identity provider (i.e., this program) and
// the database where audits will be store. If no database exists nil will be returned.
func providerPrincipal(sqlDB *sql.DB) (security.Principal, auditor.BlessingLogReader) {
	// TODO(ashankar): Somewhat silly to have to create a runtime, but oh-well.
	r, err := rt.New()
	if err != nil {
		vlog.Fatal(err)
	}
	defer r.Cleanup()
	p := r.Principal()
	if sqlDB == nil {
		return p, nil
	}
	auditor, reader, err := auditor.NewSQLBlessingAuditor(sqlDB)
	if err != nil {
		vlog.Fatalf("Failed to create sql auditor from config: %v", err)
	}
	return audit.NewPrincipal(p, auditor), reader
}

func dbFromConfigDatabase(database string) (*sql.DB, error) {
	db, err := sql.Open("mysql", database+"?parseTime=true")
	if err != nil {
		return nil, fmt.Errorf("failed to create database with database(%v): %v", database, err)
	}
	if err := db.Ping(); err != nil {
		return nil, err
	}
	return db, nil
}

func httpaddress() string {
	_, port, err := net.SplitHostPort(*httpaddr)
	if err != nil {
		vlog.Fatalf("Failed to parse %q: %v", *httpaddr, err)
	}
	return fmt.Sprintf("https://%s:%v", *host, port)
}

var tmpl = template.Must(template.New("main").Parse(`<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<title>Veyron Identity Server</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css">
</head>
<body>
<div class="container">
<div class="page-header"><h2>{{.Self}}</h2><h4>A Veyron Blessing Provider</h4></div>
<div class="well">
This is a Veyron identity provider that provides blessings with the name prefix <mark>{{.Self}}</mark>.
<br/>
The public key of this provider is {{.Self.PublicKey}}, which is available in <a class="btn btn-xs btn-primary" href="/pubkey/">DER</a> encoded
<a href="http://en.wikipedia.org/wiki/X.690#DER_encoding">format</a>.
</div>

<div class="well">
<ul>
{{if .GoogleServers}}
<li>Blessings (using Google OAuth to fetch an email address) are provided via Veyron RPCs to: <tt>{{range .GoogleServers}}{{.}}{{end}}</tt></li>
{{end}}
{{if .DischargeServers}}
<li>RevocationCaveat Discharges are provided via Veyron RPCs to: <tt>{{range .DischargeServers}}{{.}}{{end}}</tt></li>
{{end}}
{{if .ListBlessingsRoute}}
<li>You can <a class="btn btn-xs btn-primary" href="/google/{{.ListBlessingsRoute}}">enumerate</a> blessings provided with your
email address.</li>
{{end}}
</ul>
</div>

</div>
</body>
</html>`))
