Beispiel #1
0
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)
}
Beispiel #2
0
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)
		})
	}
}
Beispiel #3
0
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)
		})
	}
}
Beispiel #4
0
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)
		})
	}
}
Beispiel #5
0
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)
}
Beispiel #6
0
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)
}
Beispiel #7
0
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)
}