예제 #1
0
func (c *clientResource) create(w http.ResponseWriter, r *http.Request) {
	ct := r.Header.Get("content-type")
	if ct != "application/json" {
		log.Debugf("Unsupported request content-type: %v", ct)
		writeAPIError(w, http.StatusBadRequest, newAPIError(errorInvalidRequest, "unsupported content-type"))
		return
	}

	var sc schema.Client
	dec := json.NewDecoder(r.Body)
	err := dec.Decode(&sc)
	if err != nil {
		log.Debugf("Error decoding request body: %v", err)
		writeAPIError(w, http.StatusBadRequest, newAPIError(errorInvalidRequest, "unable to decode request body"))
		return
	}

	ci, err := schema.MapSchemaClientToClientIdentity(sc)
	if err != nil {
		log.Debugf("Invalid request data: %v", err)
		writeAPIError(w, http.StatusBadRequest, newAPIError(errorInvalidClientMetadata, "missing or invalid field: redirectURIs"))
		return
	}

	if err := ci.Metadata.Valid(); err != nil {
		log.Debugf("ClientMetadata invalid: %v", err)
		writeAPIError(w, http.StatusBadRequest, newAPIError(errorInvalidClientMetadata, err.Error()))
		return
	}

	clientID, err := oidc.GenClientID(ci.Metadata.RedirectURIs[0].Host)
	if err != nil {
		log.Errorf("Failed generating ID for new client: %v", err)
		writeAPIError(w, http.StatusInternalServerError, newAPIError(errorServerError, "unable to generate client ID"))
		return
	}

	creds, err := c.repo.New(clientID, ci.Metadata)
	if err != nil {
		log.Errorf("Failed creating client: %v", err)
		writeAPIError(w, http.StatusInternalServerError, newAPIError(errorServerError, "unable to create client"))
		return
	}
	ci.Credentials = *creds

	ssc := schema.MapClientIdentityToSchemaClientWithSecret(ci)
	w.Header().Add("Location", phttp.NewResourceLocation(r.URL, ci.Credentials.ID))
	writeResponseWithBody(w, http.StatusCreated, ssc)
}
예제 #2
0
파일: connector_ldap.go 프로젝트: ryanj/dex
func (m *LDAPIdentityProvider) LDAPConnect() (*ldap.Conn, error) {
	var err error
	var ldapConn *ldap.Conn

	log.Debugf("LDAPConnect()")
	if m.useSSL {
		ldapConn, err = ldap.DialTLS("tcp", fmt.Sprintf("%s:%d", m.serverHost, m.serverPort), m.tlsConfig)
		if err != nil {
			return nil, err
		}
	} else {
		ldapConn, err = ldap.Dial("tcp", fmt.Sprintf("%s:%d", m.serverHost, m.serverPort))
		if err != nil {
			return nil, err
		}
		if m.useTLS {
			err = ldapConn.StartTLS(m.tlsConfig)
			if err != nil {
				return nil, err
			}
		}
	}

	return ldapConn, err
}
예제 #3
0
func (p *LDAPPool) ldapConnect() (*ldap.Conn, error) {
	var err error
	var ldapConn *ldap.Conn

	log.Debugf("LDAPConnect()")
	if p.UseSSL {
		ldapConn, err = ldap.DialTLS("tcp", fmt.Sprintf("%s:%d", p.ServerHost, p.ServerPort), p.TLSConfig)
		if err != nil {
			return nil, err
		}
	} else {
		ldapConn, err = ldap.Dial("tcp", fmt.Sprintf("%s:%d", p.ServerHost, p.ServerPort))
		if err != nil {
			return nil, err
		}
		if p.UseTLS {
			err = ldapConn.StartTLS(p.TLSConfig)
			if err != nil {
				return nil, err
			}
		}
	}

	return ldapConn, err
}
예제 #4
0
파일: oidc.go 프로젝트: otsimo/accounts
func (n *pcsStepNext) step(fn pcsStepFunc) (next pcsStepper) {
	ttl, err := fn()
	if err == nil {
		next = &pcsStepNext{aft: ttl}
		log.Debugf("Refreshed jwt, next attempt in %v", next.after())
	} else {
		next = &pcsStepRetry{aft: time.Second}
		log.Errorf("JWT refresh failed, retrying in %v: %v", next.after(), err)
	}
	return
}
예제 #5
0
파일: grpc.go 프로젝트: otsimo/accounts
func (s *grpcServer) authToken(jwt jose.JWT) (string, *oidc.ClientMetadata, error) {
	ciRepo := s.server.ClientIdentityRepo
	keys, err := s.server.KeyManager.PublicKeys()
	if err != nil {
		log.Errorf("grpc.go: Failed to get keys: %v", err)
		return "", nil, errors.New("errorAccessDenied")
	}
	if len(keys) == 0 {
		log.Error("grpc.go: No keys available for verification client")
		return "", nil, errors.New("errorAccessDenied")
	}

	ok, err := oidc.VerifySignature(jwt, keys)
	if err != nil {
		log.Errorf("grpc.go: Failed to verify signature: %v", err)
		return "", nil, err
	}
	if !ok {
		log.Info("grpc.go: token signature is not verified")
		return "", nil, errors.New("invalid token")
	}

	clientID, err := oidc.VerifyClientClaims(jwt, s.server.IssuerURL.String())
	if err != nil {
		log.Errorf("grpc.go: Failed to verify JWT claims: %v", err)
		return "", nil, errors.New("failed to verify jwt claims token")
	}

	md, err := ciRepo.Metadata(clientID)
	if md == nil || err != nil {
		log.Errorf("grpc.go: Failed to find clientID: %s, error=%v", clientID, err)
		return "", nil, err
	}
	//client must be admin in order to use login and register grpc apis.
	ok, err = ciRepo.IsDexAdmin(clientID)
	if err != nil {
		return "", nil, err
	}

	if !ok {
		log.Infof("grpc.go: Client [%s] is not admin", clientID)
		return "", nil, errors.New("errorAccessDenied")
	}

	log.Debugf("grpc.go: Authenticated token for client ID %s", clientID)
	return clientID, md, nil
}
예제 #6
0
파일: main.go 프로젝트: adrianlop/dex
func main() {
	fs := flag.NewFlagSet("dex-worker", flag.ExitOnError)
	listen := fs.String("listen", "http://127.0.0.1:5556", "the address that the server will listen on")

	issuer := fs.String("issuer", "http://127.0.0.1:5556", "the issuer's location")

	certFile := fs.String("tls-cert-file", "", "the server's certificate file for TLS connection")
	keyFile := fs.String("tls-key-file", "", "the server's private key file for TLS connection")

	templates := fs.String("html-assets", "./static/html", "directory of html template files")

	emailTemplateDirs := flagutil.StringSliceFlag{"./static/email"}
	fs.Var(&emailTemplateDirs, "email-templates", "comma separated list of directories of email template files")

	emailFrom := fs.String("email-from", "", "emails sent from dex will come from this address")
	emailConfig := fs.String("email-cfg", "./static/fixtures/emailer.json", "configures emailer.")

	enableRegistration := fs.Bool("enable-registration", false, "Allows users to self-register")

	noDB := fs.Bool("no-db", false, "manage entities in-process w/o any encryption, used only for single-node testing")

	// UI-related:
	issuerName := fs.String("issuer-name", "dex", "The name of this dex installation; will appear on most pages.")
	issuerLogoURL := fs.String("issuer-logo-url", "https://coreos.com/assets/images/brand/coreos-wordmark-135x40px.png", "URL of an image representing the issuer")

	// ignored if --no-db is set
	dbURL := fs.String("db-url", "", "DSN-formatted database connection string")

	keySecrets := pflag.NewBase64List(32)
	fs.Var(keySecrets, "key-secrets", "A comma-separated list of base64 encoded 32 byte strings used as symmetric keys used to encrypt/decrypt signing key data in DB. The first key is considered the active key and used for encryption, while the others are used to decrypt.")

	useOldFormat := fs.Bool("use-deprecated-secret-format", false, "In prior releases, the database used AES-CBC to encrypt keys. New deployments should use the default AES-GCM encryption.")

	dbMaxIdleConns := fs.Int("db-max-idle-conns", 0, "maximum number of connections in the idle connection pool")
	dbMaxOpenConns := fs.Int("db-max-open-conns", 0, "maximum number of open connections to the database")

	// used only if --no-db is set
	connectors := fs.String("connectors", "./static/fixtures/connectors.json", "JSON file containg set of IDPC configs")
	clients := fs.String("clients", "./static/fixtures/clients.json", "json file containing set of clients")
	users := fs.String("users", "./static/fixtures/users.json", "json file containing set of users")

	logDebug := fs.Bool("log-debug", false, "log debug-level information")
	logTimestamps := fs.Bool("log-timestamps", false, "prefix log lines with timestamps")

	if err := fs.Parse(os.Args[1:]); err != nil {
		fmt.Fprintln(os.Stderr, err.Error())
		os.Exit(1)
	}

	if err := pflag.SetFlagsFromEnv(fs, "DEX_WORKER"); err != nil {
		fmt.Fprintln(os.Stderr, err.Error())
		os.Exit(1)
	}

	if *logDebug {
		log.EnableDebug()
		log.Infof("Debug logging enabled.")
		log.Debugf("Debug logging enabled.")
	}
	if *logTimestamps {
		log.EnableTimestamps()
	}

	// Validate listen address.
	lu, err := url.Parse(*listen)
	if err != nil {
		log.Fatalf("Invalid listen address %q: %v", *listen, err)
	}

	switch lu.Scheme {
	case "http":
	case "https":
		if *certFile == "" || *keyFile == "" {
			log.Fatalf("Must provide certificate file and private key file")
		}
	default:
		log.Fatalf("Only 'http' and 'https' schemes are supported")
	}

	// Validate issuer address.
	iu, err := url.Parse(*issuer)
	if err != nil {
		log.Fatalf("Invalid issuer URL %q: %v", *issuer, err)
	}

	if iu.Scheme != "http" && iu.Scheme != "https" {
		log.Fatalf("Only 'http' and 'https' schemes are supported")
	}

	scfg := server.ServerConfig{
		IssuerURL:          *issuer,
		TemplateDir:        *templates,
		EmailTemplateDirs:  emailTemplateDirs,
		EmailFromAddress:   *emailFrom,
		EmailerConfigFile:  *emailConfig,
		IssuerName:         *issuerName,
		IssuerLogoURL:      *issuerLogoURL,
		EnableRegistration: *enableRegistration,
	}

	if *noDB {
		log.Warning("Running in-process without external database or key rotation")
		scfg.StateConfig = &server.SingleServerConfig{
			ClientsFile:    *clients,
			ConnectorsFile: *connectors,
			UsersFile:      *users,
		}
	} else {
		if len(keySecrets.BytesSlice()) == 0 {
			log.Fatalf("Must specify at least one key secret")
		}
		if *dbMaxIdleConns == 0 {
			log.Warning("Running with no limit on: database idle connections")
		}
		if *dbMaxOpenConns == 0 {
			log.Warning("Running with no limit on: database open connections")
		}
		dbCfg := db.Config{
			DSN:                *dbURL,
			MaxIdleConnections: *dbMaxIdleConns,
			MaxOpenConnections: *dbMaxOpenConns,
		}
		scfg.StateConfig = &server.MultiServerConfig{
			KeySecrets:     keySecrets.BytesSlice(),
			DatabaseConfig: dbCfg,
			UseOldFormat:   *useOldFormat,
		}
	}

	srv, err := scfg.Server()
	if err != nil {
		log.Fatalf("Unable to build Server: %v", err)
	}

	var cfgs []connector.ConnectorConfig
	var sleep time.Duration
	for {
		var err error
		cfgs, err = srv.ConnectorConfigRepo.All()
		if len(cfgs) > 0 && err == nil {
			break
		}
		sleep = ptime.ExpBackoff(sleep, 8*time.Second)
		if err != nil {
			log.Errorf("Unable to load connectors, retrying in %v: %v", sleep, err)
		} else {
			log.Errorf("No connectors, will wait. Retrying in %v.", sleep)
		}
		time.Sleep(sleep)
	}

	for _, cfg := range cfgs {
		cfg := cfg
		if err = srv.AddConnector(cfg); err != nil {
			log.Fatalf("Failed registering connector: %v", err)
		}
	}

	h := srv.HTTPHandler()

	h = handlers.LoggingHandler(log.InfoWriter(), h)

	httpsrv := &http.Server{
		Addr:    lu.Host,
		Handler: h,
	}

	log.Infof("Binding to %s...", httpsrv.Addr)
	go func() {
		if lu.Scheme == "http" {
			log.Fatal(httpsrv.ListenAndServe())
		} else {
			log.Fatal(httpsrv.ListenAndServeTLS(*certFile, *keyFile))
		}
	}()

	<-srv.Run()
}
예제 #7
0
파일: invitation.go 프로젝트: Tecsisa/dex
func (h *InvitationHandler) handleGET(w http.ResponseWriter, r *http.Request) {
	q := r.URL.Query()
	token := q.Get("token")

	keys, err := h.keysFunc()
	if err != nil {
		log.Errorf("internal error getting public keys: %v", err)
		writeAPIError(w, http.StatusInternalServerError, newAPIError(errorServerError,
			"There's been an error processing your request."))
		return
	}

	invite, err := user.ParseAndVerifyInvitationToken(token, h.issuerURL, keys)
	if err != nil {
		log.Debugf("invalid invitation token: %v (%v)", err, token)
		writeAPIError(w, http.StatusBadRequest, newAPIError(errorInvalidRequest,
			"Your invitation could not be verified"))
		return
	}

	_, err = h.um.VerifyEmail(invite)
	if err != nil && err != manager.ErrorEmailAlreadyVerified {
		// Allow AlreadyVerified folks to pass through- otherwise
		// folks who encounter an error after passing this point will
		// never be able to set their passwords.
		log.Debugf("error attempting to verify email: %v", err)
		switch err {
		case user.ErrorNotFound:
			writeAPIError(w, http.StatusBadRequest, newAPIError(errorInvalidRequest,
				"Your email does not match the email address on file"))
			return
		default:
			log.Errorf("internal error verifying email: %v", err)
			writeAPIError(w, http.StatusInternalServerError, newAPIError(errorServerError,
				"There's been an error processing your request."))
			return
		}
	}

	passwordReset := invite.PasswordReset(h.issuerURL, h.redirectValidityWindow)
	signer, err := h.signerFunc()
	if err != nil || signer == nil {
		log.Errorf("error getting signer: %v (signer: %v)", err, signer)
		writeAPIError(w, http.StatusInternalServerError, newAPIError(errorServerError,
			"There's been an error processing your request."))
		return
	}

	jwt, err := jose.NewSignedJWT(passwordReset.Claims, signer)
	if err != nil {
		log.Errorf("error constructing or signing PasswordReset from Invitation JWT: %v", err)
		writeAPIError(w, http.StatusInternalServerError, newAPIError(errorServerError,
			"There's been an error processing your request."))
		return
	}
	passwordResetToken := jwt.Encode()

	passwordResetURL := h.passwordResetURL
	newQuery := passwordResetURL.Query()
	newQuery.Set("token", passwordResetToken)
	passwordResetURL.RawQuery = newQuery.Encode()
	http.Redirect(w, r, passwordResetURL.String(), http.StatusSeeOther)
}