21 Replies Latest reply on Apr 21, 2015 9:28 AM by butch

    Getting Current User in App

      Hey guys,

       

      It's easy to get the current user in client-side javascript within an app.  Is there an easy way to get it from the node back-end?

       

      I'm currently getting the user on the front-end, then telling the server which user it is on the back-end.  That's a huge security risk.

       

      Thanks,

      Dan

        • Re: Getting Current User in App
          jrlarson

          It's only a risk when your back-end endpoints do not validate that the

          request is coming from a registered Jive instance.

           

          I'm still looking for documentation on doing that...

           

          Thanks,

           

          John

           

           

          John Larson

          Senior Director, Technology

          414 588-2765

          john.larson@7summitsagency.com

          7Summits On LinkedIn <http://www.linkedin.com/companies/7summits>

          Follow Us on Twitter <http://twitter.com/7SummitsAgency>

           

           

          On Mon, Mar 3, 2014 at 3:38 PM, Dan Bucholtz <

          • Re: Getting Current User in App
            gdinning

            You can use Spring to inject the authenticationProvider bean into your class.  Then, just call getJiveUser() on the auth provider.

            • Re: Getting Current User in App
              aron.racho

              Hi there,

               

              Its possible to 'lock down' your node sdk routes such that it checks for the presence of a jiveEXTN header, for any secured calls made from the app using osapi.http.get/post with authz: signed. You could make a signed call back to the middleware service with the current user, and then have the service call jive to verify its authenticity. The middleware service will validate the jiveEXTN header to make sure that the call is being made from a trusted jive instance.

               

              Let me know if this approach works for you.

               

              Aron

                • Re: Getting Current User in App

                  Seems a little hacky but I'll take what I can get.  I'm not above hacky.

                    • Re: Getting Current User in App

                      Let me try and clarify Aron Racho answer a bit...

                       

                      When Jive looks for the html of the view to render for a tile action, configuration, et. we sign that with the jiveEXTN information. From within an app, when you do an osapi.http.xxxx (get/post/put/delete), you can also specify the request to be signed. Because the iframe that's rendered has a security token on it, Jive knows the request from the browser is legit. The request from Jive to your service will be signed with the key/secret and will include context information. You can validate this signature using the HMAC-SHA-256 encryption (the node sdk does this for you). In production, this is required to flow over HTTPs so the combination of signing and TLS ensures the request isn't spoofed and is valid. This is, essentially, the Signed Fetch pattern defined by OAuth and used by OpenSocial.

                      jiveSignedFetch.png

                      1 person found this helpful
                        • Re: Getting Current User in App

                          I should also have mentioned that Aron Racho talks about "locking" the routes here Securing multiple Jive communities to same node.js backend?

                          However, we don't pass, as part of the context, the current user. We've got a feature request open for this and we're trying to get this into the next release. In the meantime, you can send a POST from your app into jive that has the user id.

                          1 person found this helpful
                          • Re: Getting Current User in App
                            cgum

                            I had to figure out how to validate the signature as well, but I'm working in Java.  I found the code in the jive-sdk that was doing this in JavaScript and ported it to Java...  I'll share, should anyone need just the function to do it.

                                /*
                            
                            import javax.crypto.Mac;
                            import javax.crypto.spec.SecretKeySpec;
                            import java.io.*;
                            import java.net.URLDecoder;
                            import java.security.GeneralSecurityException;
                            import java.security.InvalidKeyException;
                            import java.security.NoSuchAlgorithmException;
                            
                                 */
                            
                                public boolean validateAuthSignature(String auth, String clientSecret)
                                        throws NoSuchAlgorithmException, UnsupportedEncodingException, InvalidKeyException  {
                            
                                    String[] authVars = auth.split(" ");
                                    String authFlag = authVars[0];
                                    if ("JiveEXTN".equals(authFlag)) {
                                        String str = "";
                                        String[] authParams = authVars[1].split("&");
                                        String signature = null;
                                        for(String p : authParams) {
                                            if (p.indexOf("signature") == 0) {
                                                signature = p.split("signature=")[1];
                                            } else {
                                                if (str.length() > 0) {
                                                    str += '&';
                                                }
                                                str += p;
                                            }
                                        }
                                        if (signature == null) return false;
                            
                                        Mac sha256_HMAC = Mac.getInstance("HmacSHA256");
                                        byte[] keyBytes = Base64.decodeBase64(clientSecret);
                                        SecretKeySpec secret_key = new SecretKeySpec(keyBytes, "HmacSHA256");
                                        sha256_HMAC.init(secret_key);
                                        byte[] hashBytes = sha256_HMAC.doFinal(str.getBytes());
                                        String hash = Base64.encodeBase64String(hashBytes);
                                        return hash.equals(URLDecoder.decode(signature, "UTF-8"));
                                    }
                                    return false;
                                }
                            
                            
                            
                              • Re: Getting Current User in App
                                butch

                                Simple method for PHP

                                 

                                Usage:  Jive::Authenticate(...);

                                 

                                class Jive {

                                  /**

                                  * Sign a string with a clientSecret using a specific algorithm

                                  *

                                  * @param string str String to sign

                                  * @param string secret The secret to use

                                  * @param string algorithm The hashing algorithm to use

                                  *

                                  * @result string The string signed with the secret

                                  */

                                  static public function Sign($str, $secret, $algorithm = 'sha256') {

                                  $decodedClientSecret = base64_decode($secret);

                                  $hash_hmac = hash_hmac($algorithm, $str, $decodedClientSecret, true);

                                  return base64_encode($hash_hmac);

                                  }

                                 

                                 

                                  /**

                                  * Authenticate an authorizationheader

                                  *

                                  * @param string clientSecret Client secret from the Jive instance

                                  * e.g. 1xz2e8e1y6wmemu898079u03vooc7q6c.s

                                  * @param string authorizationHeader The Authorization header sent from Jive

                                  * e.g. Authorization:  algorithm=HmacSHA256&client_id=hy5ay42oakkvz9iz3ynfcopreq2jewtc.i&jive_url=https%3A%2F%2Fjive-butch.polldev.com%3A8443&tenant_id=76406c34-5df8-432f-a869-59192cacdafd-dev&timestamp=1429631304339&signature=pPta88C6K7gtXjs7SeAVwatjU58RGqk4GSG7EAkYFNU%3D

                                  *

                                  * @result boolean true/false - Whether we can trust the authorization header for this clientSecret

                                  */

                                  static public function Authenticate($clientSecret, $authorizationHeader) {

                                  $parts = explode("JiveEXTN ", $authorizationHeader);

                                  $authorization = isset($parts[1])? $parts[1] : "";

                                  $paramMap = array();

                                  if (strlen($authorization) > 0) {

                                  parse_str($parts[1], $paramMap);

                                  }

                                  $paramStrWithoutSignature = substr($authorization, 0, strpos($authorization, "&signature="));

                                 

                                 

                                  $signature = $paramMap["signature"];

                                  $algorithm = $paramMap["algorithm"];

                                  $clientId = $paramMap["client_id"];

                                  $jiveUrl = $paramMap["jive_url"];

                                  $tenantId = $paramMap["tenant_id"];

                                  $timeStampStr = $paramMap["timestamp"];

                                 

                                 

                                  $expectedSignature = Jive::Sign($paramStrWithoutSignature, $clientSecret);

                                 

                                 

                                  return ($expectedSignature == $signature);

                                  }

                                }

                        • Re: Getting Current User in App

                          To add to Aron's response, Jive adds the following headers to every signed request from the app:

                           

                          X-Jive-User-Email

                          X-Jive-User-ID

                          X-Jive-User-External

                          X-Jive-Apps-Market-ID

                           

                          the user id can then be used in any Core API calls that need it.

                          • Re: Getting Current User in App
                            macanhhuy

                            hello Aron Racho ,

                             

                            I make request

                            osapi.http.get(

                            { "href":"http://mybackend.com/some/service/call", "authz":"signed" }

                            ).execute(
                            function(data){
                            console.log(data)

                            )

                            And i received the data like this

                            http:/app-home-server.example.com/signed-fetch?my_app_param=val&oauth_consumer_key=myAppKey&

                            oauth_nonce=7sGE00xSfY4PBStICbXyPbIliNymOhu2&oauth_signature_method=HMAC-SHA1&

                            oauth_timestamp=1290013827&oauth_version=1.0&opensocial_app_id=my_app_id&

                            opensocial_app_url=&opensocial_owner_id=1001@jive_id_N&opensocial_viewer_id=1001@jive_id_N&

                            oauth_signature=N7mODAf9OJ1DXQRPisRqGK4DNMo=

                             

                             

                            I used this code for my backend and i always received signature invalid

                            Jive Apps Developer Community: Using OAuth in your applications oauth-demo-server.tar.gz

                             

                            How can i receive the jiveEXTN header? I know i can get

                            Authorization: "JiveEXTN algorithm=HmacSHA256&client_id=...&jive_url=...&tenant_id=...&timestamp=1385749129911&signature=..."

                            X-Forwarded-For: "..., ..."

                            X-Forwarded-Proto: "http"

                            X-Jive-Apps-Market-ID: "..."

                            X-Jive-User-Email: "..."

                            X-Jive-User-External: "false"

                            X-Jive-User-ID: "..."

                            X-shindig-dos: "on"


                            but i cannot see it when i print all headers in backend code.


                            Thanks,

                             

                             


                              • Re: Getting Current User in App

                                Your request is one coming from an application that was installed through the Jive apps market (using Oauth1 for request signing).

                                 

                                This discussion is about apps delivered as part of a Jive Addon. While both look the same on the client side of development, the interaction with a backend server via osapi.http calls or signed request is very different

                                • Re: Getting Current User in App
                                  Ryan Rutan

                                  Sorry for the delay here.   JiveEXTN isn't a header itself, as much as its a marker.  It is used as a prefix marker in the Authorization header.  When present, the remaining contents of the authorization after "JiveEXTN " should be used as a "querystring" per say and used as parameters for the validation sequence.  Does that help? 

                                • Re: Getting Current User in App

                                  I wrote a passport oauth plugin to enable sessions and securing routes properly w/o examining the jive headers, etc.

                                   

                                  Check it out at https://github.com/danbucholtz/passport-oauth-jive

                                   

                                  I'll add an example later this week when I get time.  It is very easy to use, just like the google oauth passport plugins.

                                   

                                  I'd love some feedback on how to hook into more interesting things like getting a user's permission groups or custom functionality without that stuff living in the library itself.