func getEnv() { listenOn = fmt.Sprintf( "%s:%s", env.Getenv("HOST", ""), env.Getenv("PORT", "4443"), ) accessTokenLifetime = env.Getenv("OAUTH2_ACCESS_TOKEN_LIFETIME", "3600") forceHTTP = env.Getenv("DANGEROUSLY_FORCE_HTTP", "") hostURL = env.Getenv("HOST_URL", "https://localhost:4443") providers = []provider.Provider{ dropbox.New( "dropbox", env.Getenv("DROPBOX_CLIENT", ""), env.Getenv("DROPBOX_SECRET", ""), pkg.JoinURL(hostURL, "/oauth2/auth"), ), signin.New( "login", env.Getenv("SIGNIN_URL", ""), pkg.JoinURL(hostURL, "/oauth2/auth"), ), } bcryptWorkFactor = env.Getenv("BCRYPT_WORKFACTOR", "10") databaseURL = env.Getenv("DATABASE_URL", "") locations = map[string]string{ "signUp": env.Getenv("SIGNUP_URL", ""), "signIn": env.Getenv("SIGNIN_URL", ""), } jwtPrivateKeyPath = env.Getenv("JWT_PRIVATE_KEY_PATH", path.Join(os.Getenv("GOPATH"), "src", "github.com", "ory-am", "hydra", "example", "cert", "rs256-private.pem")) jwtPublicKeyPath = env.Getenv("JWT_PUBLIC_KEY_PATH", path.Join(os.Getenv("GOPATH"), "src", "github.com", "ory-am", "hydra", "example", "cert", "rs256-public.pem")) tlsKeyPath = env.Getenv("TLS_KEY_PATH", path.Join(os.Getenv("GOPATH"), "src", "github.com", "ory-am", "hydra", "example", "cert", "tls-key.pem")) tlsCertPath = env.Getenv("TLS_CERT_PATH", path.Join(os.Getenv("GOPATH"), "src", "github.com", "ory-am", "hydra", "example", "cert", "tls-cert.pem")) }
func isValidAuthorizeRequest(c *HTTPClient, ar *AuthorizeRequest, retry bool) (bool, error) { request := gorequest.New() resp, body, errs := request.Post(pkg.JoinURL(c.ep, "/guard/allowed")).SetBasicAuth(c.clientConfig.ClientID, c.clientConfig.ClientSecret).Set("Content-Type", "application/json").Send(*ar).End() if len(errs) > 0 { return false, errors.Errorf("Got errors: %v", errs) } else if retry && resp.StatusCode == http.StatusUnauthorized { var err error if c.clientToken, err = c.clientConfig.Token(oauth2.NoContext); err != nil { return false, errors.New(err) } else if c.clientToken == nil { return false, errors.New("Access token could not be retrieved") } return isValidAuthorizeRequest(c, ar, false) } else if resp.StatusCode != http.StatusOK { return false, errors.Errorf("Status code %d is not 200: %s", resp.StatusCode, body) } if err := json.Unmarshal([]byte(body), &isAllowed); err != nil { return false, errors.Errorf("Could not unmarshall body because %s", err.Error()) } if !isAllowed.Allowed { return false, errors.New("Authroization denied") } return isAllowed.Allowed, nil }
func isValidAuthenticationRequest(c *HTTPClient, token string, retry bool) (bool, error) { data := url.Values{} data.Set("token", token) request := gorequest.New() resp, body, errs := request.Post(pkg.JoinURL(c.ep, "/oauth2/introspect")).Type("form").SetBasicAuth(c.clientConfig.ClientID, c.clientConfig.ClientSecret).SendString(data.Encode()).End() if len(errs) > 0 { return false, errors.Errorf("Got errors: %v", errs) } else if resp.StatusCode != http.StatusOK { return false, errors.Errorf("Status code %d is not 200: %s", resp.StatusCode, body) } if retry && resp.StatusCode == http.StatusUnauthorized { var err error if c.clientToken, err = c.clientConfig.Token(oauth2.NoContext); err != nil { return false, errors.New(err) } else if c.clientToken == nil { return false, errors.New("Access token could not be retrieved") } return isValidAuthenticationRequest(c, token, false) } else if resp.StatusCode != http.StatusOK { return false, fmt.Errorf("Status code %d is not 200", resp.StatusCode) } var introspect struct { Active bool `json:"active"` } if err := json.Unmarshal([]byte(body), &introspect); err != nil { return false, err } else if !introspect.Active { return false, errors.New("Authentication denied") } return introspect.Active, nil }
func New(endpoint, client, secret string) *HTTPClient { return &HTTPClient{ ep: endpoint, clientConfig: &clientcredentials.Config{ ClientSecret: secret, ClientID: client, TokenURL: pkg.JoinURL(endpoint, "oauth2/token"), }, clientToken: &oauth2.Token{}, } }
func JoinURLStrings(host string, args ...string) string { return pkg.JoinURL(host, args...) }
func (h *Handler) AuthorizeHandler(w http.ResponseWriter, r *http.Request) { r.ParseForm() resp := h.server.NewResponse() defer resp.Close() code := r.Form.Get("code") state := r.Form.Get("state") if code != "" { stateData, err := h.States.GetStateData(state) if err != nil { // Something else went wrong http.Error(w, fmt.Sprintf("Could not fetch state: %s", err), http.StatusBadRequest) return } if stateData.IsExpired() { http.Error(w, fmt.Sprintf("This session expired %v.", err), http.StatusBadRequest) } r.Form = stateData.ToURLValues() } if ar := h.server.HandleAuthorizeRequest(resp, r); ar != nil { // For now, a provider must be given. // TODO there should be a fallback provider which is a redirect to the login endpoint. This should be configurable by env var. // Let's see if this is a valid provider. If not, return an error. providerName := r.Form.Get("provider") if r.Form.Get("provider") == "" && h.SignInLocation != "" { providerName = "login" } provider, err := h.Providers.Find(providerName) if err != nil { http.Error(w, fmt.Sprintf(`Unknown provider "%s".`, providerName), http.StatusBadRequest) return } if code == "" { stateData := new(storage.StateData) if err := stateData.FromAuthorizeRequest(ar, provider.GetID()); err != nil { // Something else went wrong http.Error(w, fmt.Sprintf("Could not hydrate state data: %s", err), http.StatusInternalServerError) return } stateData.ExpireInOneHour() if err := h.States.SaveStateData(stateData); err != nil { // Something else went wrong http.Error(w, fmt.Sprintf("Could not persist state data: %s", err), http.StatusInternalServerError) return } // If no code was given we have to initiate the provider's authorization workflow url := provider.GetAuthenticationURL(stateData.ID) http.Redirect(w, r, url, http.StatusFound) return } // Create a session by exchanging the code for the auth code session, err := provider.FetchSession(code) if err != nil { http.Error(w, fmt.Sprintf("Could not exchange access code: %s", err), http.StatusUnauthorized) return } var conn connection.Connection var acc account.Account if session.GetForcedLocalSubject() != "" { acc, err = h.Accounts.Get(session.GetForcedLocalSubject()) } else { conn, err = h.Connections.FindByRemoteSubject(provider.GetID(), session.GetRemoteSubject()) } if err == pkg.ErrNotFound { // The subject is not linked to any account. if h.SignUpLocation == "" { http.Error(w, "No sign up location is set. Please contact your admin.", http.StatusInternalServerError) return } redirect, err := url.Parse(h.SignUpLocation) if err != nil { http.Error(w, fmt.Sprintf("Could not parse redirect URL: %s", err), http.StatusInternalServerError) return } claims := map[string]interface{}{ "iss": h.Issuer, "aud": redirect.String(), "exp": time.Now().Add(time.Hour), "iat": time.Now(), "state": ar.State, "connector_id": provider.GetID(), "connector_response": session.GetExtra(), "connector_subject": session.GetRemoteSubject(), "redirect_uri": pkg.JoinURL(h.HostURL, "oauth2/authorize"), } authToken, err := h.JWT.SignToken(claims, map[string]interface{}{}) if err != nil { http.Error(w, fmt.Sprintf("Could not generate token: %s", err), http.StatusInternalServerError) return } query := redirect.Query() query.Add("auth_token", authToken) redirect.RawQuery = query.Encode() log.WithFields(log.Fields{ "provider": provider.GetID(), "subject": session.GetRemoteSubject(), "redirect": h.SignUpLocation, }).Warnf(`Remote subject is not linked to any local subject. Redirecting to sign up page.`) http.Redirect(w, r, redirect.String(), http.StatusFound) return } else if err != nil { // Something else went wrong http.Error(w, fmt.Sprintf("Could not assert subject claim: %s", err), http.StatusInternalServerError) return } var localSubject string if conn != nil { localSubject = conn.GetLocalSubject() } else if acc != nil { localSubject = acc.GetID() } ar.UserData = jwt.NewClaimsCarrier(uuid.New(), h.Issuer, localSubject, ar.Client.GetId(), time.Now().Add(time.Duration(ar.Expiration)*time.Second), time.Now(), time.Now()) ar.Authorized = true h.server.FinishAuthorizeRequest(resp, r, ar) } if resp.IsError { resp.StatusCode = http.StatusUnauthorized } osin.OutputJSON(resp, w, r) }