Exemplo n.º 1
0
func main() {
	flag.Parse()
	log.SetFlags(0)

	if *connectURL == "" {
		log.Fatal("Invalid Connection URL")
	}

	u, err := url.Parse(*connectURL)
	if err != nil {
		log.Fatal("Unable to Parse URL", err)
	}
	qsh := utils.GetQsh("GET", u.Path, "", "")

	var header = make(http.Header)
	token := utils.Sign(*appSecret, *appID, qsh)
	if token != "" {
		header.Add("Authorization", "Bearer "+token)
	}

	c, resp, err := websocket.DefaultDialer.Dial(*connectURL, header)
	if err != nil {
		log.Fatal("Unable to connect to ", *connectURL, ", HTTP Response: ", resp.Status)
	}
	defer c.Close()
	log.Printf("connected to %s", *connectURL)

	done := make(chan struct{})

	go func() {
		defer c.Close()
		defer close(done)
		for {
			_, message, err := c.ReadMessage()
			if err != nil {
				log.Println("read:", err)
				return
			}
			log.Printf("recv: %s", message)
		}
	}()
	for {
		time.Sleep(time.Second)
	}
}
Exemplo n.º 2
0
// VerifyHandler is a Middleware to handle Claims and JWT verification. JWT is
// generated at Client side so this Middleware does additional validations
// compared to simple JWT verification.
func VerifyHandler(h http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		// If Auth is not enabled, do not verify any details
		if !utils.RestConfig.AuthEnabled {
			h.ServeHTTP(w, r)
			return
		}

		// This flag will be used to expire JWT quickly ignoring exp claim in JWT
		quickExpire := false

		// Collect Authorization header, validate if format is different
		// than "Bearer <TOKEN>"
		authHeader := strings.TrimSpace(r.Header.Get("Authorization"))
		authHeaderParts := []string{"", ""}
		if authHeader != "" {
			authHeaderParts = strings.Split(authHeader, " ")
			if len(authHeaderParts) != 2 || strings.ToLower(authHeaderParts[0]) != "bearer" {
				http.Error(w, "Authorization header format must be Bearer <TOKEN>", 401)
				return
			}
		} else {
			// Special case for Websocket URLs, when connected through Javascript
			// it can't send headers along with the connection. So access token sent
			// as query parameter token=<TOKEN>. Collect the JWT token and set quickExpire
			// flag to expire the token quickly irespective of exp set in Claims
			eventsURL := "/" + utils.RestConfig.APIVersion + utils.RestConfig.EventsURL
			if r.URL.Path == eventsURL {
				authHeaderParts[1] = r.URL.Query().Get("token")
				if authHeaderParts[1] != "" {
					quickExpire = true
				}
			}
		}

		// Claims["qsh"] is SHA256 hash generated by Client, this will
		// change wrt URL,Method and parameters. Generate qsh by using
		// User inputs, this will be compared with Claims["qsh"]
		buf := new(bytes.Buffer)
		buf.ReadFrom(r.Body)
		qsh := utils.GetQsh(r.Method, r.URL.Path, r.URL.Query().Encode(), buf.String())

		// Verify JWT token with additional validations for Claims
		token, err := jwt.Parse(authHeaderParts[1], func(token *jwt.Token) (interface{}, error) {
			// Error if required claims are not sent by Client
			for _, claimName := range requiredClaims {
				if _, ok := token.Claims[claimName]; !ok {
					return nil, fmt.Errorf("Token missing %s Claim", claimName)
				}
			}

			// When App ID/Name not present in Apps list - Unauthorized
			if _, ok := utils.RestApps[token.Claims["iss"].(string)]; !ok {
				return nil, fmt.Errorf("Invalid App ID: %v", token.Claims["iss"])
			}

			// Validate the JWT Signing Algo
			if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
				return nil, fmt.Errorf("Unexpected signing method: %v", token.Header["alg"])
			}

			// When qsh don't Match
			if qsh != token.Claims["qsh"] {
				return nil, errors.New("Invalid qsh claim in token")
			}
			return []byte(utils.RestApps[token.Claims["iss"].(string)]), nil
		})

		if err != nil || !token.Valid {
			http.Error(w, err.Error(), http.StatusUnauthorized)
			return
		}

		// Special Case for Internal APIs Only AppId:gluster can send message
		internalURL := "/" + utils.RestConfig.APIVersion + utils.RestConfig.ListenURL
		if token.Claims["iss"] != utils.RestConfig.InternalUser && r.URL.Path == internalURL {
			http.Error(w, http.StatusText(403), 403)
			return
		}

		// TODO: Expiry override. If Websocket request then expire the token in 30 secs
		if quickExpire {
			now := time.Now().Unix()
			exp, err := time.Parse(time.UnixDate, fmt.Sprintf("%d", token.Claims["iat"]))
			if err != nil {
				http.Error(w, "Error calculating Expiry", 401)
				return
			}

			if now > exp.Add(time.Second*utils.RestConfig.WebsocketExpiry).Unix() {
				http.Error(w, "Token expired", 401)
				return
			}
		}

		h.ServeHTTP(w, r)
	})
}