Beispiel #1
0
func NewOAuthPasswordAuthenticator(provider Provider, mapper authapi.UserIdentityMapper) (authenticator.Password, error) {
	clientConfig, err := provider.NewConfig()
	if err != nil {
		return nil, err
	}

	// unused for password grants
	clientConfig.RedirectUrl = "/"

	client, err := osincli.NewClient(clientConfig)
	if err != nil {
		return nil, err
	}

	transport, err := provider.GetTransport()
	if err != nil {
		return nil, err
	}
	client.Transport = transport

	return &Handler{
		provider:     provider,
		clientConfig: clientConfig,
		client:       client,
		mapper:       mapper,
	}, nil
}
Beispiel #2
0
func NewExternalOAuthRedirector(provider Provider, state State, redirectURL string, success handlers.AuthenticationSuccessHandler, errorHandler handlers.AuthenticationErrorHandler, mapper authapi.UserIdentityMapper) (*Handler, error) {
	clientConfig, err := provider.NewConfig()
	if err != nil {
		return nil, err
	}

	clientConfig.RedirectUrl = redirectURL

	client, err := osincli.NewClient(clientConfig)
	if err != nil {
		return nil, err
	}

	transport, err := provider.GetTransport()
	if err != nil {
		return nil, err
	}
	client.Transport = transport

	return &Handler{
		provider:     provider,
		state:        state,
		clientConfig: clientConfig,
		client:       client,
		success:      success,
		errorHandler: errorHandler,
		mapper:       mapper,
	}, nil
}
Beispiel #3
0
func main() {
	config := &osincli.ClientConfig{
		ClientId:                 "xxxxxxxxxxxx.apps.googleusercontent.com",
		ClientSecret:             "secret",
		AuthorizeUrl:             "https://accounts.google.com/o/oauth2/auth",
		TokenUrl:                 "https://accounts.google.com/o/oauth2/token",
		RedirectUrl:              "http://localhost:14001/appauth",
		ErrorsInStatusCode:       true,
		SendClientSecretInParams: true,
		Scope: "https://www.googleapis.com/auth/plus.login",
	}
	client, err := osincli.NewClient(config)
	if err != nil {
		panic(err)
	}

	// create a new request to generate the url
	areq := client.NewAuthorizeRequest(osincli.CODE)
	areq.CustomParameters["access_type"] = "online"
	areq.CustomParameters["approval_prompt"] = "auto"

	// Home
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		u := areq.GetAuthorizeUrl()
		w.Write([]byte(fmt.Sprintf("<a href=\"%s\">Login</a>", u.String())))
	})

	// Auth endpoint
	http.HandleFunc("/appauth", func(w http.ResponseWriter, r *http.Request) {
		// parse a token request
		if areqdata, err := areq.HandleRequest(r); err == nil {
			treq := client.NewAccessRequest(osincli.AUTHORIZATION_CODE, areqdata)

			// show access request url (for debugging only)
			u2 := treq.GetTokenUrl()
			w.Write([]byte(fmt.Sprintf("Access token URL: %s\n\n", u2.String())))

			// exchange the authorize token for the access token
			ad, err := treq.GetToken()
			if err == nil {
				w.Write([]byte(fmt.Sprintf("Access token: %+v\n\n", ad)))

				AccessPlusApi(ad, w)
			} else {
				w.Write([]byte(fmt.Sprintf("ERROR: %s\n", err)))
			}
		} else {
			w.Write([]byte(fmt.Sprintf("ERROR: %s\n", err)))
		}
	})

	http.ListenAndServe(":14001", nil)
}
Beispiel #4
0
func main() {
	config := &osincli.ClientConfig{
		ClientId:     "1234",
		ClientSecret: "aabbccdd",
		AuthorizeUrl: "http://localhost:14000/authorize",
		TokenUrl:     "http://localhost:14000/token",
		RedirectUrl:  "http://localhost:14001/appauth",
	}
	client, err := osincli.NewClient(config)
	if err != nil {
		panic(err)
	}

	// create a new request to generate the url
	areq := client.NewAuthorizeRequest(osincli.CODE)

	// Home
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		u := areq.GetAuthorizeUrl()

		w.Write([]byte(fmt.Sprintf("<a href=\"%s\">Login</a>", u.String())))
	})

	// Auth endpoint
	http.HandleFunc("/appauth", func(w http.ResponseWriter, r *http.Request) {
		// parse a token request
		if areqdata, err := areq.HandleRequest(r); err == nil {
			treq := client.NewAccessRequest(osincli.AUTHORIZATION_CODE, areqdata)

			// show access request url (for debugging only)
			u2 := treq.GetTokenUrl()
			w.Write([]byte(fmt.Sprintf("Access token URL: %s\n", u2.String())))

			// exchange the authorize token for the access token
			ad, err := treq.GetToken()
			if err == nil {
				w.Write([]byte(fmt.Sprintf("Access token: %+v\n", ad)))
			} else {
				w.Write([]byte(fmt.Sprintf("ERROR: %s\n", err)))
			}
		} else {
			w.Write([]byte(fmt.Sprintf("ERROR: %s\n", err)))
		}
	})

	http.ListenAndServe(":14001", nil)
}
Beispiel #5
0
func TestRegistryAndServer(t *testing.T) {
	ch := make(chan *http.Request, 1)
	assertServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
		ch <- req
	}))

	validClient := &oapi.OAuthClient{
		ObjectMeta:   kapi.ObjectMeta{Name: "test"},
		Secret:       "secret",
		RedirectURIs: []string{assertServer.URL + "/assert"},
	}
	validClientAuth := &oapi.OAuthClientAuthorization{
		UserName:   "******",
		ClientName: "test",
	}

	testCases := map[string]struct {
		Client      *oapi.OAuthClient
		ClientAuth  *oapi.OAuthClientAuthorization
		AuthSuccess bool
		AuthUser    user.Info
		Scope       string
		Check       func(*testHandlers, *http.Request)
	}{
		"needs auth": {
			Client: validClient,
			Check: func(h *testHandlers, _ *http.Request) {
				if !h.AuthNeed || h.GrantNeed || h.AuthErr != nil || h.GrantErr != nil {
					t.Errorf("expected request to need authentication: %#v", h)
				}
			},
		},
		"needs grant": {
			Client:      validClient,
			AuthSuccess: true,
			AuthUser: &user.DefaultInfo{
				Name: "user",
			},
			Check: func(h *testHandlers, _ *http.Request) {
				if h.AuthNeed || !h.GrantNeed || h.AuthErr != nil || h.GrantErr != nil {
					t.Errorf("expected request to need to grant access: %#v", h)
				}
			},
		},
		"has non covered grant": {
			Client:      validClient,
			AuthSuccess: true,
			AuthUser: &user.DefaultInfo{
				Name: "user",
			},
			ClientAuth: &oapi.OAuthClientAuthorization{
				UserName:   "******",
				ClientName: "test",
				Scopes:     []string{"test"},
			},
			Scope: "test other",
			Check: func(h *testHandlers, req *http.Request) {
				if h.AuthNeed || !h.GrantNeed || h.AuthErr != nil || h.GrantErr != nil {
					t.Errorf("expected request to need to grant access because of uncovered scopes: %#v", h)
				}
			},
		},
		"has covered grant": {
			Client:      validClient,
			AuthSuccess: true,
			AuthUser: &user.DefaultInfo{
				Name: "user",
			},
			ClientAuth: &oapi.OAuthClientAuthorization{
				UserName:   "******",
				ClientName: "test",
				Scopes:     []string{"test", "other"},
			},
			Scope: "test other",
			Check: func(h *testHandlers, req *http.Request) {
				if h.AuthNeed || h.GrantNeed || h.AuthErr != nil || h.GrantErr != nil {
					t.Errorf("unexpected flow: %#v", h)
				}
			},
		},
		"has auth and grant": {
			Client:      validClient,
			AuthSuccess: true,
			AuthUser: &user.DefaultInfo{
				Name: "user",
			},
			ClientAuth: validClientAuth,
			Check: func(h *testHandlers, req *http.Request) {
				if h.AuthNeed || h.GrantNeed || h.AuthErr != nil || h.GrantErr != nil {
					t.Errorf("unexpected flow: %#v", h)
					return
				}
				if req == nil {
					t.Errorf("unexpected nil assertion request")
					return
				}
				if code := req.URL.Query().Get("code"); code == "" {
					t.Errorf("expected query param 'code', got: %#v", req)
				}
			},
		},
	}

	for _, testCase := range testCases {
		h := &testHandlers{}
		h.Authenticate = testCase.AuthSuccess
		h.User = testCase.AuthUser
		access, authorize := &test.AccessTokenRegistry{}, &test.AuthorizeTokenRegistry{}
		client := &test.ClientRegistry{
			Client: testCase.Client,
		}
		if testCase.Client == nil {
			client.Err = apierrs.NewNotFound("client", "unknown")
		}
		grant := &test.ClientAuthorizationRegistry{
			ClientAuthorization: testCase.ClientAuth,
		}
		if testCase.ClientAuth == nil {
			grant.Err = apierrs.NewNotFound("clientAuthorization", "test:test")
		}
		storage := registrystorage.New(access, authorize, client, NewUserConversion())
		config := osinserver.NewDefaultServerConfig()
		server := osinserver.New(
			config,
			storage,
			osinserver.AuthorizeHandlers{
				handlers.NewAuthorizeAuthenticator(
					h,
					h,
					h,
				),
				handlers.NewGrantCheck(
					NewClientAuthorizationGrantChecker(grant),
					h,
					h,
				),
			},
			osinserver.AccessHandlers{
				handlers.NewDenyAccessAuthenticator(),
			},
			h,
		)
		mux := http.NewServeMux()
		server.Install(mux, "")
		s := httptest.NewServer(mux)

		oaclientConfig := &osincli.ClientConfig{
			ClientId:     "test",
			ClientSecret: "secret",
			RedirectUrl:  assertServer.URL + "/assert",
			AuthorizeUrl: s.URL + "/authorize",
			TokenUrl:     s.URL + "/token",
			Scope:        testCase.Scope,
		}
		oaclient, err := osincli.NewClient(oaclientConfig)
		if err != nil {
			t.Fatalf("unexpected error: %v", err)
		}

		aReq := oaclient.NewAuthorizeRequest(osincli.CODE)
		if _, err := http.Get(aReq.GetAuthorizeUrl().String()); err != nil {
			t.Fatalf("unexpected error: %v", err)
		}

		var req *http.Request
		select {
		case out := <-ch:
			req = out
		default:
		}

		testCase.Check(h, req)
	}
}
func TestAuthorizeStartFlow(t *testing.T) {
	storage := teststorage.New()
	oauthServer := New(
		NewDefaultServerConfig(),
		storage,
		AuthorizeHandlerFunc(func(ar *osin.AuthorizeRequest, w http.ResponseWriter) (bool, error) {
			ar.Authorized = true
			return false, nil
		}),
		AccessHandlerFunc(func(ar *osin.AccessRequest, w http.ResponseWriter) error {
			ar.Authorized = true
			ar.GenerateRefresh = false
			return nil
		}),
		NewDefaultErrorHandler(),
	)
	mux := http.NewServeMux()
	oauthServer.Install(mux, "")
	server := httptest.NewServer(mux)

	ch := make(chan *osincli.AccessData, 1)
	var oaclient *osincli.Client
	var authReq *osincli.AuthorizeRequest
	assertServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		data, err := authReq.HandleRequest(r)
		if err != nil {
			t.Fatalf("unexpected error: %v", err)
		}
		tokenReq := oaclient.NewAccessRequest(osincli.AUTHORIZATION_CODE, data)
		token, err := tokenReq.GetToken()
		if err != nil {
			t.Fatalf("unexpected error: %v", err)
		}
		ch <- token
	}))

	storage.Clients["test"] = &osin.DefaultClient{
		Id:          "test",
		Secret:      "secret",
		RedirectUri: assertServer.URL + "/assert",
	}
	oaclientConfig := &osincli.ClientConfig{
		ClientId:     "test",
		ClientSecret: "secret",
		RedirectUrl:  assertServer.URL + "/assert",
		AuthorizeUrl: server.URL + "/authorize",
		TokenUrl:     server.URL + "/token",
	}
	osinclient, err := osincli.NewClient(oaclientConfig)
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}
	oaclient = osinclient
	authReq = oaclient.NewAuthorizeRequest(osincli.CODE)

	config := &oauth2.Config{
		ClientID:     "test",
		ClientSecret: "",
		Scopes:       []string{"a_scope"},
		Endpoint: oauth2.Endpoint{
			AuthURL:  server.URL + "/authorize",
			TokenURL: server.URL + "/token",
		},
		RedirectURL: assertServer.URL + "/assert",
	}
	url := config.AuthCodeURL("")
	client := http.Client{ /*CheckRedirect: func(req *http.Request, via []*http.Request) error {
		t.Logf("redirect (%d): to %s, %#v", len(via), req.URL, req)
		return nil
	}*/}
	if _, err := client.Get(url); err != nil {
		t.Fatalf("unexpected error: %v", err)
	}

	token := <-ch
	if token.AccessToken == "" {
		t.Errorf("unexpected empty access token: %#v", token)
	}
}
Beispiel #7
0
// InstallAPI registers endpoints for an OAuth2 server into the provided mux,
// then returns an array of strings indicating what endpoints were started
// (these are format strings that will expect to be sent a single string value).
func (c *AuthConfig) InstallAPI(container *restful.Container) ([]string, error) {
	mux := c.getMux(container)

	clientStorage, err := clientetcd.NewREST(c.RESTOptionsGetter)
	if err != nil {
		return nil, err
	}
	clientRegistry := clientregistry.NewRegistry(clientStorage)
	combinedOAuthClientGetter := saoauth.NewServiceAccountOAuthClientGetter(c.KubeClient, c.KubeClient, clientRegistry)

	accessTokenStorage, err := accesstokenetcd.NewREST(c.RESTOptionsGetter, combinedOAuthClientGetter, c.EtcdBackends...)
	if err != nil {
		return nil, err
	}
	accessTokenRegistry := accesstokenregistry.NewRegistry(accessTokenStorage)

	authorizeTokenStorage, err := authorizetokenetcd.NewREST(c.RESTOptionsGetter, combinedOAuthClientGetter, c.EtcdBackends...)
	if err != nil {
		return nil, err
	}
	authorizeTokenRegistry := authorizetokenregistry.NewRegistry(authorizeTokenStorage)

	clientAuthStorage, err := clientauthetcd.NewREST(c.RESTOptionsGetter, combinedOAuthClientGetter)
	if err != nil {
		return nil, err
	}
	clientAuthRegistry := clientauthregistry.NewRegistry(clientAuthStorage)

	errorPageHandler, err := c.getErrorHandler()
	if err != nil {
		glog.Fatal(err)
	}

	authRequestHandler, authHandler, authFinalizer, err := c.getAuthorizeAuthenticationHandlers(mux, errorPageHandler)
	if err != nil {
		glog.Fatal(err)
	}

	storage := registrystorage.New(accessTokenRegistry, authorizeTokenRegistry, combinedOAuthClientGetter, registry.NewUserConversion())
	config := osinserver.NewDefaultServerConfig()
	if c.Options.TokenConfig.AuthorizeTokenMaxAgeSeconds > 0 {
		config.AuthorizationExpiration = c.Options.TokenConfig.AuthorizeTokenMaxAgeSeconds
	}
	if c.Options.TokenConfig.AccessTokenMaxAgeSeconds > 0 {
		config.AccessExpiration = c.Options.TokenConfig.AccessTokenMaxAgeSeconds
	}

	grantChecker := registry.NewClientAuthorizationGrantChecker(clientAuthRegistry)
	grantHandler := c.getGrantHandler(mux, authRequestHandler, combinedOAuthClientGetter, clientAuthRegistry)

	server := osinserver.New(
		config,
		storage,
		osinserver.AuthorizeHandlers{
			handlers.NewAuthorizeAuthenticator(
				authRequestHandler,
				authHandler,
				errorPageHandler,
			),
			handlers.NewGrantCheck(
				grantChecker,
				grantHandler,
				errorPageHandler,
			),
			authFinalizer,
		},
		osinserver.AccessHandlers{
			handlers.NewDenyAccessAuthenticator(),
		},
		osinserver.NewDefaultErrorHandler(),
	)
	server.Install(mux, OpenShiftOAuthAPIPrefix)

	if err := CreateOrUpdateDefaultOAuthClients(c.Options.MasterPublicURL, c.AssetPublicAddresses, clientRegistry); err != nil {
		glog.Fatal(err)
	}
	browserClient, err := clientRegistry.GetClient(kapi.NewContext(), OpenShiftBrowserClientID)
	if err != nil {
		glog.Fatal(err)
	}
	osOAuthClientConfig := c.NewOpenShiftOAuthClientConfig(browserClient)
	osOAuthClientConfig.RedirectUrl = c.Options.MasterPublicURL + path.Join(OpenShiftOAuthAPIPrefix, tokenrequest.DisplayTokenEndpoint)

	osOAuthClient, _ := osincli.NewClient(osOAuthClientConfig)
	if len(*c.Options.MasterCA) > 0 {
		rootCAs, err := cmdutil.CertPoolFromFile(*c.Options.MasterCA)
		if err != nil {
			glog.Fatal(err)
		}

		osOAuthClient.Transport = knet.SetTransportDefaults(&http.Transport{
			TLSClientConfig: &tls.Config{RootCAs: rootCAs},
		})
	}

	tokenRequestEndpoints := tokenrequest.NewEndpoints(c.Options.MasterPublicURL, osOAuthClient)
	tokenRequestEndpoints.Install(mux, OpenShiftOAuthAPIPrefix)

	// glog.Infof("oauth server configured as: %#v", server)
	// glog.Infof("auth handler: %#v", authHandler)
	// glog.Infof("auth request handler: %#v", authRequestHandler)
	// glog.Infof("grant checker: %#v", grantChecker)
	// glog.Infof("grant handler: %#v", grantHandler)

	return []string{
		fmt.Sprintf("Started OAuth2 API at %%s%s", OpenShiftOAuthAPIPrefix),
	}, nil
}
Beispiel #8
0
func TestOAuthStorage(t *testing.T) {
	testutil.DeleteAllEtcdKeys()

	groupMeta := registered.GroupOrDie(api.GroupName)
	etcdClient, err := testutil.MakeNewEtcdClient()
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}
	etcdHelper := etcdstorage.NewEtcdStorage(etcdClient, kapi.Codecs.LegacyCodec(groupMeta.GroupVersions...), etcdtest.PathPrefix())

	accessTokenStorage := accesstokenetcd.NewREST(etcdHelper)
	accessTokenRegistry := accesstokenregistry.NewRegistry(accessTokenStorage)
	authorizeTokenStorage := authorizetokenetcd.NewREST(etcdHelper)
	authorizeTokenRegistry := authorizetokenregistry.NewRegistry(authorizeTokenStorage)
	clientStorage := clientetcd.NewREST(etcdHelper)
	clientRegistry := clientregistry.NewRegistry(clientStorage)

	user := &testUser{UserName: "******", UserUID: "1"}
	storage := registrystorage.New(accessTokenRegistry, authorizeTokenRegistry, clientRegistry, user)

	oauthServer := osinserver.New(
		osinserver.NewDefaultServerConfig(),
		storage,
		osinserver.AuthorizeHandlerFunc(func(ar *osin.AuthorizeRequest, w http.ResponseWriter) (bool, error) {
			ar.UserData = "test"
			ar.Authorized = true
			return false, nil
		}),
		osinserver.AccessHandlerFunc(func(ar *osin.AccessRequest, w http.ResponseWriter) error {
			ar.UserData = "test"
			ar.Authorized = true
			ar.GenerateRefresh = false
			return nil
		}),
		osinserver.NewDefaultErrorHandler(),
	)
	mux := http.NewServeMux()
	oauthServer.Install(mux, "")
	server := httptest.NewServer(mux)
	defer server.Close()

	ch := make(chan *osincli.AccessData, 1)
	var oaclient *osincli.Client
	var authReq *osincli.AuthorizeRequest
	assertServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		data, err := authReq.HandleRequest(r)
		if err != nil {
			t.Fatalf("unexpected error: %v", err)
		}
		tokenReq := oaclient.NewAccessRequest(osincli.AUTHORIZATION_CODE, data)
		token, err := tokenReq.GetToken()
		if err != nil {
			t.Fatalf("unexpected error: %v", err)
		}
		ch <- token
	}))

	clientRegistry.CreateClient(kapi.NewContext(), &api.OAuthClient{
		ObjectMeta:   kapi.ObjectMeta{Name: "test"},
		Secret:       "secret",
		RedirectURIs: []string{assertServer.URL + "/assert"},
	})
	storedClient, err := storage.GetClient("test")
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}
	if storedClient.GetSecret() != "secret" {
		t.Fatalf("unexpected stored client: %#v", storedClient)
	}

	oaclientConfig := &osincli.ClientConfig{
		ClientId:     "test",
		ClientSecret: "secret",
		RedirectUrl:  assertServer.URL + "/assert",
		AuthorizeUrl: server.URL + "/authorize",
		TokenUrl:     server.URL + "/token",
	}
	osinclient, err := osincli.NewClient(oaclientConfig)
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}
	oaclient = osinclient // initialize the assert server client as well
	authReq = oaclient.NewAuthorizeRequest(osincli.CODE)

	config := &oauth2.Config{
		ClientID:     "test",
		ClientSecret: "",
		Scopes:       []string{"a_scope"},
		RedirectURL:  assertServer.URL + "/assert",
		Endpoint: oauth2.Endpoint{
			AuthURL:  server.URL + "/authorize",
			TokenURL: server.URL + "/token",
		},
	}
	url := config.AuthCodeURL("")
	client := http.Client{ /*CheckRedirect: func(req *http.Request, via []*http.Request) error {
		t.Logf("redirect (%d): to %s, %#v", len(via), req.URL, req)
		return nil
	}*/}

	resp, err := client.Get(url)
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}
	if resp.StatusCode != http.StatusOK {
		t.Fatalf("unexpected response: %#v", resp)
	}

	token := <-ch
	if token.AccessToken == "" {
		t.Errorf("unexpected access token: %#v", token)
	}

	actualToken, err := accessTokenRegistry.GetAccessToken(kapi.NewContext(), token.AccessToken)
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}
	if actualToken.UserUID != "1" || actualToken.UserName != "test" {
		t.Errorf("unexpected stored token: %#v", actualToken)
	}
}
Beispiel #9
0
// InstallAPI registers endpoints for an OAuth2 server into the provided mux,
// then returns an array of strings indicating what endpoints were started
// (these are format strings that will expect to be sent a single string value).
func (c *AuthConfig) InstallAPI(container *restful.Container) []string {
	// TODO: register into container
	mux := container.ServeMux

	accessTokenStorage := accesstokenetcd.NewREST(c.EtcdHelper)
	accessTokenRegistry := accesstokenregistry.NewRegistry(accessTokenStorage)
	authorizeTokenStorage := authorizetokenetcd.NewREST(c.EtcdHelper)
	authorizeTokenRegistry := authorizetokenregistry.NewRegistry(authorizeTokenStorage)
	clientStorage := clientetcd.NewREST(c.EtcdHelper)
	clientRegistry := clientregistry.NewRegistry(clientStorage)
	clientAuthStorage := clientauthetcd.NewREST(c.EtcdHelper)
	clientAuthRegistry := clientauthregistry.NewRegistry(clientAuthStorage)

	authRequestHandler, authHandler, authFinalizer, err := c.getAuthorizeAuthenticationHandlers(mux)
	if err != nil {
		glog.Fatal(err)
	}

	storage := registrystorage.New(accessTokenRegistry, authorizeTokenRegistry, clientRegistry, registry.NewUserConversion())
	config := osinserver.NewDefaultServerConfig()
	if c.Options.TokenConfig.AuthorizeTokenMaxAgeSeconds > 0 {
		config.AuthorizationExpiration = c.Options.TokenConfig.AuthorizeTokenMaxAgeSeconds
	}
	if c.Options.TokenConfig.AccessTokenMaxAgeSeconds > 0 {
		config.AccessExpiration = c.Options.TokenConfig.AccessTokenMaxAgeSeconds
	}

	grantChecker := registry.NewClientAuthorizationGrantChecker(clientAuthRegistry)
	grantHandler := c.getGrantHandler(mux, authRequestHandler, clientRegistry, clientAuthRegistry)

	server := osinserver.New(
		config,
		storage,
		osinserver.AuthorizeHandlers{
			handlers.NewAuthorizeAuthenticator(
				authRequestHandler,
				authHandler,
				handlers.EmptyError{},
			),
			handlers.NewGrantCheck(
				grantChecker,
				grantHandler,
				handlers.EmptyError{},
			),
			authFinalizer,
		},
		osinserver.AccessHandlers{
			handlers.NewDenyAccessAuthenticator(),
		},
		osinserver.NewDefaultErrorHandler(),
	)
	server.Install(mux, OpenShiftOAuthAPIPrefix)

	CreateOrUpdateDefaultOAuthClients(c.Options.MasterPublicURL, c.AssetPublicAddresses, clientRegistry)
	osOAuthClientConfig := c.NewOpenShiftOAuthClientConfig(&OSBrowserClientBase)
	osOAuthClientConfig.RedirectUrl = c.Options.MasterPublicURL + path.Join(OpenShiftOAuthAPIPrefix, tokenrequest.DisplayTokenEndpoint)

	osOAuthClient, _ := osincli.NewClient(osOAuthClientConfig)
	if len(*c.Options.MasterCA) > 0 {
		rootCAs, err := cmdutil.CertPoolFromFile(*c.Options.MasterCA)
		if err != nil {
			glog.Fatal(err)
		}

		osOAuthClient.Transport = kutil.SetTransportDefaults(&http.Transport{
			TLSClientConfig: &tls.Config{RootCAs: rootCAs},
		})
	}

	tokenRequestEndpoints := tokenrequest.NewEndpoints(c.Options.MasterPublicURL, osOAuthClient)
	tokenRequestEndpoints.Install(mux, OpenShiftOAuthAPIPrefix)

	// glog.Infof("oauth server configured as: %#v", server)
	// glog.Infof("auth handler: %#v", authHandler)
	// glog.Infof("auth request handler: %#v", authRequestHandler)
	// glog.Infof("grant checker: %#v", grantChecker)
	// glog.Infof("grant handler: %#v", grantHandler)

	return []string{
		fmt.Sprintf("Started OAuth2 API at %%s%s", OpenShiftOAuthAPIPrefix),
		fmt.Sprintf("Started Login endpoint at %%s%s", OpenShiftLoginPrefix),
	}
}
Beispiel #10
0
func runOAuthFlow(t *testing.T, clusterAdminClientConfig *restclient.Config, projectName string, oauthClientConfig *osincli.ClientConfig, authorizationCodes, authorizationErrors chan string, expectGrantSuccess, expectBuildSuccess bool) {
	oauthRuntimeClient, err := osincli.NewClient(oauthClientConfig)
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}
	oauthRuntimeClient.Transport = &http.Transport{
		TLSClientConfig: &tls.Config{
			InsecureSkipVerify: true,
		},
	}

	directHTTPClient := &http.Client{
		Transport: &http.Transport{
			TLSClientConfig: &tls.Config{
				InsecureSkipVerify: true,
			},
		},
	}

	// make sure we're prompted for a password
	authorizeRequest := oauthRuntimeClient.NewAuthorizeRequest(osincli.CODE)
	authorizeURL := authorizeRequest.GetAuthorizeUrlWithParams("opaque-scope")
	authorizeHTTPRequest, err := http.NewRequest("GET", authorizeURL.String(), nil)
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}
	authorizeHTTPRequest.Header.Add("X-CSRF-Token", "csrf-01")
	authorizeResponse, err := directHTTPClient.Do(authorizeHTTPRequest)
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}
	if authorizeResponse.StatusCode != http.StatusUnauthorized {
		response, _ := httputil.DumpResponse(authorizeResponse, true)
		t.Fatalf("didn't get an unauthorized:\n %v", string(response))
	}

	// first we should get a redirect to a grant flow
	authenticatedAuthorizeHTTPRequest1, err := http.NewRequest("GET", authorizeURL.String(), nil)
	authenticatedAuthorizeHTTPRequest1.Header.Add("X-CSRF-Token", "csrf-01")
	authenticatedAuthorizeHTTPRequest1.Header.Add("Authorization", "Basic "+base64.StdEncoding.EncodeToString([]byte("harold:any-pass")))
	authentictedAuthorizeResponse1, err := directHTTPClient.Transport.RoundTrip(authenticatedAuthorizeHTTPRequest1)
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}
	if authentictedAuthorizeResponse1.StatusCode != http.StatusFound {
		response, _ := httputil.DumpResponse(authentictedAuthorizeResponse1, true)
		t.Fatalf("unexpected status :\n %v", string(response))
	}

	// second we get a webpage with a prompt.  Yeah, this next bit gets nasty
	authenticatedAuthorizeHTTPRequest2, err := http.NewRequest("GET", clusterAdminClientConfig.Host+authentictedAuthorizeResponse1.Header.Get("Location"), nil)
	authenticatedAuthorizeHTTPRequest2.Header.Add("X-CSRF-Token", "csrf-01")
	authenticatedAuthorizeHTTPRequest2.Header.Add("Authorization", "Basic "+base64.StdEncoding.EncodeToString([]byte("harold:any-pass")))
	authentictedAuthorizeResponse2, err := directHTTPClient.Transport.RoundTrip(authenticatedAuthorizeHTTPRequest2)
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}
	if authentictedAuthorizeResponse2.StatusCode != http.StatusOK {
		response, _ := httputil.DumpResponse(authentictedAuthorizeResponse2, true)
		t.Fatalf("unexpected status :\n %v", string(response))
	}
	// have to parse the page to get the csrf value.  Yeah, that's nasty, I can't think of another way to do it without creating a new grant handler
	body, err := ioutil.ReadAll(authentictedAuthorizeResponse2.Body)
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}
	if !expectGrantSuccess {
		if !strings.Contains(string(body), "requested illegal scopes") {
			t.Fatalf("missing expected message: %v", string(body))
		}
		return
	}
	csrfMatches := grantCSRFRegex.FindStringSubmatch(string(body))
	if len(csrfMatches) != 2 {
		response, _ := httputil.DumpResponse(authentictedAuthorizeResponse2, false)
		t.Fatalf("unexpected body :\n %v\n%v", string(response), string(body))
	}
	thenMatches := grantThenRegex.FindStringSubmatch(string(body))
	if len(thenMatches) != 2 {
		response, _ := httputil.DumpResponse(authentictedAuthorizeResponse2, false)
		t.Fatalf("unexpected body :\n %v\n%v", string(response), string(body))
	}
	t.Logf("CSRF is %v", csrfMatches)
	t.Logf("then is %v", thenMatches)

	// third we respond and approve the grant, then let the transport follow redirects and give us the code
	postBody := strings.NewReader(url.Values(map[string][]string{
		"then":         {thenMatches[1]},
		"csrf":         {csrfMatches[1]},
		"client_id":    {oauthClientConfig.ClientId},
		"user_name":    {"harold"},
		"scopes":       {oauthClientConfig.Scope},
		"redirect_uri": {clusterAdminClientConfig.Host},
		"approve":      {"true"},
	}).Encode())
	authenticatedAuthorizeHTTPRequest3, err := http.NewRequest("POST", clusterAdminClientConfig.Host+origin.OpenShiftApprovePrefix, postBody)
	authenticatedAuthorizeHTTPRequest3.Header.Set("Content-Type", "application/x-www-form-urlencoded")
	authenticatedAuthorizeHTTPRequest3.Header.Add("X-CSRF-Token", csrfMatches[1])
	authenticatedAuthorizeHTTPRequest3.Header.Add("Authorization", "Basic "+base64.StdEncoding.EncodeToString([]byte("harold:any-pass")))
	for i := range authentictedAuthorizeResponse2.Cookies() {
		cookie := authentictedAuthorizeResponse2.Cookies()[i]
		authenticatedAuthorizeHTTPRequest3.AddCookie(cookie)
	}
	authentictedAuthorizeResponse3, err := directHTTPClient.Transport.RoundTrip(authenticatedAuthorizeHTTPRequest3)
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}
	if authentictedAuthorizeResponse3.StatusCode != http.StatusFound {
		response, _ := httputil.DumpResponse(authentictedAuthorizeResponse3, true)
		t.Fatalf("unexpected status :\n %v", string(response))
	}

	// fourth, the grant redirects us again to have us send the code to the server
	authenticatedAuthorizeHTTPRequest4, err := http.NewRequest("GET", clusterAdminClientConfig.Host+authentictedAuthorizeResponse3.Header.Get("Location"), nil)
	authenticatedAuthorizeHTTPRequest4.Header.Add("X-CSRF-Token", "csrf-01")
	authenticatedAuthorizeHTTPRequest4.Header.Add("Authorization", "Basic "+base64.StdEncoding.EncodeToString([]byte("harold:any-pass")))
	authentictedAuthorizeResponse4, err := directHTTPClient.Transport.RoundTrip(authenticatedAuthorizeHTTPRequest4)
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}
	if authentictedAuthorizeResponse4.StatusCode != http.StatusFound {
		response, _ := httputil.DumpResponse(authentictedAuthorizeResponse4, true)
		t.Fatalf("unexpected status :\n %v", string(response))
	}

	authenticatedAuthorizeHTTPRequest5, err := http.NewRequest("GET", authentictedAuthorizeResponse4.Header.Get("Location"), nil)
	authenticatedAuthorizeHTTPRequest5.Header.Add("X-CSRF-Token", "csrf-01")
	authenticatedAuthorizeHTTPRequest5.Header.Add("Authorization", "Basic "+base64.StdEncoding.EncodeToString([]byte("harold:any-pass")))
	authentictedAuthorizeResponse5, err := directHTTPClient.Do(authenticatedAuthorizeHTTPRequest5)
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}

	authorizationCode := ""
	select {
	case authorizationCode = <-authorizationCodes:
	case <-time.After(10 * time.Second):
		response, _ := httputil.DumpResponse(authentictedAuthorizeResponse5, true)
		t.Fatalf("didn't get a code:\n %v", string(response))
	}

	accessRequest := oauthRuntimeClient.NewAccessRequest(osincli.AUTHORIZATION_CODE, &osincli.AuthorizeData{Code: authorizationCode})
	accessData, err := accessRequest.GetToken()
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}

	whoamiConfig := clientcmd.AnonymousClientConfig(clusterAdminClientConfig)
	whoamiConfig.BearerToken = accessData.AccessToken
	whoamiClient, err := client.New(&whoamiConfig)
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}

	if _, err := whoamiClient.Builds(projectName).List(kapi.ListOptions{}); !kapierrors.IsForbidden(err) && !expectBuildSuccess {
		t.Fatalf("unexpected error: %v", err)
	}

	user, err := whoamiClient.Users().Get("~")
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}
	if user.Name != "harold" {
		t.Fatalf("expected %v, got %v", "harold", user.Name)
	}
}
Beispiel #11
0
func main() {
	// create http muxes
	serverhttp := http.NewServeMux()
	clienthttp := http.NewServeMux()

	// create server
	config := osin.NewServerConfig()
	sstorage := example.NewTestStorage()
	sstorage.SetClient("1234", &osin.DefaultClient{
		Id:          "1234",
		Secret:      "aabbccdd",
		RedirectUri: "http://localhost:14001/appauth",
	})
	server := osin.NewServer(config, sstorage)

	// create client
	cliconfig := &osincli.ClientConfig{
		ClientId:     "1234",
		ClientSecret: "aabbccdd",
		AuthorizeUrl: "http://localhost:14000/authorize",
		TokenUrl:     "http://localhost:14000/token",
		RedirectUrl:  "http://localhost:14001/appauth",
	}
	client, err := osincli.NewClient(cliconfig)
	if err != nil {
		panic(err)
	}

	// create a new request to generate the url
	areq := client.NewAuthorizeRequest(osincli.CODE)

	// SERVER

	// Authorization code endpoint
	serverhttp.HandleFunc("/authorize", func(w http.ResponseWriter, r *http.Request) {
		resp := server.NewResponse()
		defer resp.Close()

		if ar := server.HandleAuthorizeRequest(resp, r); ar != nil {
			if !example.HandleLoginPage(ar, w, r) {
				return
			}
			ar.Authorized = true
			server.FinishAuthorizeRequest(resp, r, ar)
		}
		if resp.IsError && resp.InternalError != nil {
			fmt.Printf("ERROR: %s\n", resp.InternalError)
		}
		osin.OutputJSON(resp, w, r)
	})

	// Access token endpoint
	serverhttp.HandleFunc("/token", func(w http.ResponseWriter, r *http.Request) {
		resp := server.NewResponse()
		defer resp.Close()

		if ar := server.HandleAccessRequest(resp, r); ar != nil {
			ar.Authorized = true
			server.FinishAccessRequest(resp, r, ar)
		}
		if resp.IsError && resp.InternalError != nil {
			fmt.Printf("ERROR: %s\n", resp.InternalError)
		}
		osin.OutputJSON(resp, w, r)
	})

	// Information endpoint
	serverhttp.HandleFunc("/info", func(w http.ResponseWriter, r *http.Request) {
		resp := server.NewResponse()
		defer resp.Close()

		if ir := server.HandleInfoRequest(resp, r); ir != nil {
			server.FinishInfoRequest(resp, r, ir)
		}
		osin.OutputJSON(resp, w, r)
	})

	// CLIENT

	// Home
	clienthttp.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		u := areq.GetAuthorizeUrl()

		w.Write([]byte(fmt.Sprintf("<a href=\"%s\">Login</a>", u.String())))
	})

	// Auth endpoint
	clienthttp.HandleFunc("/appauth", func(w http.ResponseWriter, r *http.Request) {
		// parse a token request
		areqdata, err := areq.HandleRequest(r)
		if err != nil {
			w.Write([]byte(fmt.Sprintf("ERROR: %s\n", err)))
			return
		}

		treq := client.NewAccessRequest(osincli.AUTHORIZATION_CODE, areqdata)

		// show access request url (for debugging only)
		u2 := treq.GetTokenUrl()
		w.Write([]byte(fmt.Sprintf("Access token URL: %s\n", u2.String())))

		// exchange the authorize token for the access token
		ad, err := treq.GetToken()
		if err != nil {
			w.Write([]byte(fmt.Sprintf("ERROR: %s\n", err)))
			return
		}
		w.Write([]byte(fmt.Sprintf("Access token: %+v\n", ad)))
	})

	go http.ListenAndServe(":14001", clienthttp)
	http.ListenAndServe(":14000", serverhttp)
}
Beispiel #12
0
func runOAuthFlow(
	t *testing.T,
	clusterAdminClientConfig *restclient.Config,
	projectName string,
	oauthClientConfig *osincli.ClientConfig,
	inputFilter htmlutil.InputFilterFunc,
	authorizationCodes chan string,
	authorizationErrors chan string,
	expectGrantSuccess bool,
	expectBuildSuccess bool,
	expectOperations []string,
) {
	drain(authorizationCodes)
	drain(authorizationErrors)

	oauthRuntimeClient, err := osincli.NewClient(oauthClientConfig)
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}
	testTransport := &basicAuthTransport{rt: &http.Transport{TLSClientConfig: &tls.Config{InsecureSkipVerify: true}}}
	oauthRuntimeClient.Transport = testTransport

	authorizeRequest := oauthRuntimeClient.NewAuthorizeRequest(osincli.CODE)
	req, err := http.NewRequest("GET", authorizeRequest.GetAuthorizeUrlWithParams("opaque-state").String(), nil)
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}

	operations := []string{}
	jar, _ := cookiejar.New(nil)
	directHTTPClient := &http.Client{
		Transport: testTransport,
		CheckRedirect: func(redirectReq *http.Request, via []*http.Request) error {
			glog.Infof("302 Location: %s", redirectReq.URL.String())
			req = redirectReq
			operations = append(operations, "redirect to "+redirectReq.URL.Path)
			return nil
		},
		Jar: jar,
	}

	for {
		glog.Infof("%s %s", req.Method, req.URL.String())
		operations = append(operations, req.Method+" "+req.URL.Path)

		// Always set the csrf header
		req.Header.Set("X-CSRF-Token", "1")
		resp, err := directHTTPClient.Do(req)
		if err != nil {
			glog.Infof("%#v", operations)
			glog.Infof("%#v", jar)
			glog.Errorf("Error %v\n%#v\n%#v", err, err, resp)
			t.Errorf("Error %v\n%#v\n%#v", err, err, resp)
			return
		}
		defer resp.Body.Close()

		// Save the current URL for reference
		currentURL := req.URL

		if resp.StatusCode == 401 {
			// Set up a username and password once we're challenged
			testTransport.username = "******"
			testTransport.password = "******"
			operations = append(operations, "received challenge")
			continue
		}

		if resp.StatusCode != 200 {
			responseDump, _ := httputil.DumpResponse(resp, true)
			t.Errorf("Unexpected response %s", string(responseDump))
			return
		}

		doc, err := html.Parse(resp.Body)
		if err != nil {
			t.Error(err)
			return
		}
		forms := htmlutil.GetElementsByTagName(doc, "form")
		// if there's a single form, submit it
		if len(forms) > 1 {
			t.Errorf("More than one form encountered: %d", len(forms))
			return
		}
		if len(forms) == 0 {
			break
		}
		req, err = htmlutil.NewRequestFromForm(forms[0], currentURL, inputFilter)
		if err != nil {
			t.Error(err)
			return
		}
		operations = append(operations, "form")
	}

	authorizationCode := ""
	select {
	case authorizationCode = <-authorizationCodes:
		operations = append(operations, "code")
	case authorizationError := <-authorizationErrors:
		operations = append(operations, "error:"+authorizationError)
	case <-time.After(5 * time.Second):
		t.Error("didn't get a code or an error")
	}

	if len(authorizationCode) > 0 {
		accessRequest := oauthRuntimeClient.NewAccessRequest(osincli.AUTHORIZATION_CODE, &osincli.AuthorizeData{Code: authorizationCode})
		accessData, err := accessRequest.GetToken()
		if err != nil {
			t.Errorf("unexpected error: %v", err)
			return
		}
		operations = append(operations, fmt.Sprintf("scope:%v", accessData.ResponseData["scope"]))

		whoamiConfig := clientcmd.AnonymousClientConfig(clusterAdminClientConfig)
		whoamiConfig.BearerToken = accessData.AccessToken
		whoamiClient, err := client.New(&whoamiConfig)
		if err != nil {
			t.Errorf("unexpected error: %v", err)
			return
		}

		_, err = whoamiClient.Builds(projectName).List(kapi.ListOptions{})
		if expectBuildSuccess && err != nil {
			t.Errorf("unexpected error: %v", err)
			return
		}
		if !expectBuildSuccess && !kapierrors.IsForbidden(err) {
			t.Errorf("expected forbidden error, got %v", err)
			return
		}

		user, err := whoamiClient.Users().Get("~")
		if err != nil {
			t.Errorf("unexpected error: %v", err)
			return
		}
		if user.Name != "harold" {
			t.Errorf("expected %v, got %v", "harold", user.Name)
			return
		}
	}

	if !reflect.DeepEqual(operations, expectOperations) {
		t.Errorf("Expected:\n%#v\nGot\n%#v", expectOperations, operations)
	}

}