func (h *Handler) TokenHandler(w http.ResponseWriter, r *http.Request) { resp := h.server.NewResponse() r.ParseForm() defer resp.Close() if ar := h.server.HandleAccessRequest(resp, r); ar != nil { switch ar.Type { case osin.AUTHORIZATION_CODE: data, ok := ar.UserData.(string) if !ok { http.Error(w, fmt.Sprintf("Could not assert UserData to string: %v", ar.UserData), http.StatusInternalServerError) return } var claims jwt.ClaimsCarrier if err := json.Unmarshal([]byte(data), &claims); err != nil { http.Error(w, fmt.Sprintf("Could not unmarshal UserData: %v", ar.UserData), http.StatusInternalServerError) return } ar.UserData = jwt.NewClaimsCarrier(uuid.New(), claims.GetSubject(), h.Issuer, h.Audience, time.Now(), time.Now()) ar.Authorized = true case osin.REFRESH_TOKEN: data, ok := ar.UserData.(map[string]interface{}) if !ok { http.Error(w, fmt.Sprintf("Could not assert UserData type: %v", ar.UserData), http.StatusInternalServerError) return } claims := jwt.ClaimsCarrier(data) ar.UserData = jwt.NewClaimsCarrier(uuid.New(), claims.GetSubject(), h.Issuer, h.Audience, time.Now(), time.Now()) ar.Authorized = true case osin.PASSWORD: // TODO if !ar.Client.isAllowedToAuthenticateUser // TODO ... return // TODO } if user, err := h.authenticate(w, r, ar.Username, ar.Password); err == nil { ar.UserData = jwt.NewClaimsCarrier(uuid.New(), user.GetID(), h.Issuer, h.Audience, time.Now(), time.Now()) ar.Authorized = true } case osin.CLIENT_CREDENTIALS: ar.UserData = jwt.NewClaimsCarrier(uuid.New(), ar.Client.GetId(), h.Issuer, h.Audience, time.Now(), time.Now()) ar.Authorized = true // TODO ASSERTION workflow http://leastprivilege.com/2013/12/23/advanced-oauth2-assertion-flow-why/ // TODO Since assertions are only a draft for now and there is no need for SAML or similar this is postponed. //case osin.ASSERTION: // if ar.AssertionType == "urn:hydra" && ar.Assertion == "osin.data" { // ar.Authorized = true // } } h.server.FinishAccessRequest(resp, r, ar) } if resp.IsError { resp.StatusCode = http.StatusUnauthorized } osin.OutputJSON(resp, w, r) }
func mockAuthorization(c test) func(h hcon.ContextHandler) hcon.ContextHandler { return func(h hcon.ContextHandler) hcon.ContextHandler { return hcon.ContextHandlerFunc(func(ctx context.Context, rw http.ResponseWriter, req *http.Request) { claims := hjwt.NewClaimsCarrier(uuid.New(), "hydra", c.subject, "tests", time.Now(), time.Now()) ctx = hcon.NewContextFromAuthValues(ctx, claims, &c.token, c.policies) h.ServeHTTPContext(ctx, rw, req) }) } }
func mockAuthorization(subject string, token *jwt.Token) func(h chd.ContextHandler) chd.ContextHandler { return func(h chd.ContextHandler) chd.ContextHandler { return chd.ContextHandlerFunc(func(ctx context.Context, rw http.ResponseWriter, req *http.Request) { claims := hjwt.NewClaimsCarrier(uuid.New(), "hydra", subject, "tests", time.Now().Add(time.Hour), time.Now(), time.Now()) ctx = authcon.NewContextFromAuthValues(ctx, claims, token, []policy.Policy{}) h.ServeHTTPContext(ctx, rw, req) }) } }
func mockContext(c test) func(chd.ContextHandler) chd.ContextHandler { return func(next chd.ContextHandler) chd.ContextHandler { return chd.ContextHandlerFunc(func(ctx context.Context, rw http.ResponseWriter, req *http.Request) { claims := hjwt.NewClaimsCarrier(uuid.New(), "hydra", c.subject, "tests", time.Now().Add(time.Hour), time.Now(), time.Now()) ctx = authcon.NewContextFromAuthValues(ctx, claims, c.token, c.policies) next.ServeHTTPContext(ctx, rw, req) }) } }
func (h *Handler) AuthorizeHandler(w http.ResponseWriter, r *http.Request) { resp := h.server.NewResponse() defer resp.Close() 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. provider, err := h.Providers.Find(r.URL.Query().Get("provider")) if err != nil { http.Error(w, fmt.Sprintf(`Provider "%s" not known.`, err), http.StatusBadRequest) return } // This could be made configurable with `connection.GetCodeKeyName()` code := r.URL.Query().Get("access_code") if code == "" { // If no code was given we have to initiate the provider's authorization workflow url := provider.GetAuthCodeURL(ar) http.Redirect(w, r, url, http.StatusFound) return } // Create a session by exchanging the code for the auth code connection, err := provider.Exchange(code) if err != nil { http.Error(w, fmt.Sprintf("Could not exchange access code: %s", err), http.StatusUnauthorized) return } subject := connection.GetRemoteSubject() user, err := h.Connections.FindByRemoteSubject(provider.GetID(), subject) if err == account.ErrNotFound { // The subject is not linked to any account. http.Error(w, "Provided token is not linked to any existing account.", http.StatusUnauthorized) return } else if err != nil { // Something else went wrong http.Error(w, fmt.Sprintf("Could assert subject claim: %s", err), http.StatusInternalServerError) return } ar.UserData = jwt.NewClaimsCarrier(uuid.New(), user.GetLocalSubject(), h.Issuer, h.Audience, 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) }
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) }
func (h *Handler) TokenHandler(w http.ResponseWriter, r *http.Request) { resp := h.server.NewResponse() defer resp.Close() if ar := h.server.HandleAccessRequest(resp, r); ar != nil { switch ar.Type { case osin.AUTHORIZATION_CODE: data, ok := ar.UserData.(string) if !ok { log.WithField("UserData", fmt.Sprintf("%v", ar.UserData)).Warn("Could not assert UserData to string") } else { var claims jwt.ClaimsCarrier if err := json.Unmarshal([]byte(data), &claims); err != nil { http.Error(w, fmt.Sprintf("Could not unmarshal UserData: %v", ar.UserData), http.StatusInternalServerError) } else { ar.UserData = jwt.NewClaimsCarrier(uuid.New(), h.Issuer, claims.GetSubject(), ar.Client.GetId(), time.Now().Add(time.Duration(ar.Expiration)*time.Second), time.Now(), time.Now()) ar.Authorized = true } } case osin.REFRESH_TOKEN: data, ok := ar.UserData.(string) if !ok { http.Error(w, fmt.Sprintf("Could not assert UserData to string: %v", ar.UserData), http.StatusInternalServerError) } else { var claims jwt.ClaimsCarrier if err := json.Unmarshal([]byte(data), &claims); err != nil { http.Error(w, fmt.Sprintf("Could not unmarshal UserData: %v", ar.UserData), http.StatusInternalServerError) } else { ar.UserData = jwt.NewClaimsCarrier(uuid.New(), h.Issuer, claims.GetSubject(), ar.Client.GetId(), time.Now().Add(time.Duration(ar.Expiration)*time.Second), time.Now(), time.Now()) ar.Authorized = true } } case osin.PASSWORD: // TODO if !ar.Client.isAllowedToAuthenticateUser // TODO ... return // TODO } if user, err := h.authenticate(w, r, ar.Username, ar.Password); err == nil { ar.UserData = jwt.NewClaimsCarrier(uuid.New(), h.Issuer, user.GetID(), ar.Client.GetId(), time.Now().Add(time.Duration(ar.Expiration)*time.Second), time.Now(), time.Now()) ar.Authorized = true } case osin.CLIENT_CREDENTIALS: ar.UserData = jwt.NewClaimsCarrier(uuid.New(), h.Issuer, ar.Client.GetId(), ar.Client.GetId(), time.Now().Add(time.Duration(ar.Expiration)*time.Second), time.Now(), time.Now()) ar.Authorized = true // TODO #29 ASSERTION workflow http://leastprivilege.com/2013/12/23/advanced-oauth2-assertion-flow-why/ // Since assertions are only a draft for now and there is no need for SAML or similar this is postponed. // case osin.ASSERTION: // if ar.AssertionType == "urn:hydra" && ar.Assertion == "osin.data" { // ar.Authorized = true // } } h.server.FinishAccessRequest(resp, r, ar) } if resp.IsError { log.WithFields(log.Fields{ "code": resp.StatusCode, "id": resp.ErrorId, "message": resp.StatusText, "osinInternalError": resp.InternalError, }).Warnf("Token request failed.") resp.StatusCode = http.StatusUnauthorized } osin.OutputJSON(resp, w, r) }