服务器到服务器auth请求给出“错误”:“invalid_grant”,“error_description”:“错误请求”

时间:2015-04-10 19:27:08

标签: coldfusion

我实际上在Cold Fusion中使用Java库。我收到“错误”:“invalid_grant”,“error_description”:“错误请求”。

我已经验证了我的EPOCH,标题和声明是正确的base64编码。如果我可以使用样本p12和其他数据来匹配输出,那么我可以验证我的问题。我真的需要一些帮助。以下是我在Adobe CF9上使用的样本coldfusion脚本。

    <cfscript>
    component displayname="GoogleOauth2" output="false"
    {
        variables.my.p12FileLocation = ""; //your p12 file location goes here
        variables.my.emailOfServiceAccount = ''; //the email address listed on Google Developer's console for your project and service account goes here (https://cloud.google.com/console?redirected=true#/project)
        variables.my.scopesForToken = ''; //list of services to authorize token for (i.e. https://www.googleapis.com/auth/admin.directory.user) 
        variables.my.emailOfSuperAccount = ''; //email of super account...seemingly needed for the scope I was was requesting...
        variables.my.googleOauthURL = 'https://accounts.google.com/o/oauth2/token';

        public GoogleOauth2 function init () {
            if (structKeyExists(arguments,'p12FileLocation')){
                variables.my.p12FileLocation = arguments.p12FileLocation;
            }
            if (structKeyExists(arguments,'emailOfServiceAccount')){
                variables.my.emailOfServiceAccount = arguments.emailOfServiceAccount;
            }
            if (structKeyExists(arguments,'emailOfSuperAccount')){
                variables.my.emailOfSuperAccount = arguments.emailOfSuperAccount;
            }
            if (structKeyExists(arguments,'p12FileLocation')){
                variables.my.p12FileLocation = arguments.p12FileLocation;
            }
            return this;
        }

        public struct function getToken() {

            if (structKeyExists(arguments,'scopesForToken')){
                variables.my.scopesForToken = arguments.scopesForToken
            }

            //create the JWT Packet
            local.JWTPacket = assembleJWTPacket();

            //send it to Google
            local.result = sendPacket(JWT=local.JWTPacket);;

            try {
                //set the return token to a variable
                local.returnJson = DeserializeJSON(result.fileContent.toString());
                local.token = returnJson.access_token;
                local.returnPkg = {"token"=local.token,"success"=true};
            }
            catch(any e) {
                local.returnPkg = {"success"=false};
            }

            return local.returnPkg;
        }

        private struct function sendPacket(required string JWT ) {
            /* get token from Google */
            local.httpService = new http();
            local.httpService.setMethod("post");
            local.httpService.setCharset("utf-8");
            local.httpService.setUrl("#variables.my.googleOauthURL#");
            local.httpService.addParam(type="header",name="Content-Type",value="application/x-www-form-urlencoded");
            local.httpService.addParam(type="formfield",name="grant_type",value="urn:ietf:params:oauth:grant-type:jwt-bearer");
            local.httpService.addParam(type="formfield",name="assertion",value="#arguments.jwt#");
            local.result = httpService.send().getPrefix();

            return local.result;

        }

        private string function assembleJWTPacket() {
            //first create the header hard code the base64 value since there is only one
            // same as {"alg":"RS256","typ":"JWT"} in base64
             local.jwtHeader = 'eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9';
             //use epoch time and one hour more for duration of token...exp could be dynamic under 60 minutes
             local.epoch = dateDiff('s', dateConvert('utc2Local', createDateTime(1970, 1, 1, 0, 0, 0)), now());
             local.exp = dateDiff('s', dateConvert('utc2Local', createDateTime(1970, 1, 1, 0, 0, 0)), dateAdd('n',60,now()));

             //claim set includes email from developers console, scope which is service you want to access, and authorization time up to one hour
             local.jwtClaimSet = serializeJSON({
               "iss"=variables.my.emailOfServiceAccount,
               "scope"=variables.my.scopesForToken,
               "aud"=variables.my.googleOauthURL,
               "exp"=local.exp,
               "iat"=local.epoch,
               "sub"=variables.my.emailOfSuperAccount
            });
            // base 64 and url encode it
            local.jwtClaimSet = Base64URLEncode(jwtClaimSet);
            // combine header and claim set to be signed
            local.signString = '#jwtHeader#.#jwtClaimSet#';

            //sign it
            local.signedString = signTheString(String=local.signString);
            //encode it
            local.encodedSignedString = Base64URLEncode(String=toString(local.signedString));

            //you now have enough to send full jwt to google to get a token back
            local.jwt = '#local.jwtHeader#.#local.jwtClaimSet#.#local.encodedSignedString#';

            return local.jwt;
        }

        private array function signTheString(required string String ) {
            //get the certificate (p12) and extract the privateKey
            // create input file stream from certificate
            local.fileStream = CreateObject( "java", "java.io.FileInputStream" ).init( variables.my.p12FileLocation );
            local.keystore = CreateObject( "java", "java.security.KeyStore" ).getInstance("PKCS12");
            //password from google never changes...hard coded for now
            local.password = "notasecret";
            local.keystore.load(fileStream, password.toCharArray());
            local.key = local.keystore.getKey("privatekey", password.toCharArray());
            //now you've got the key
            local.privateKey = local.key.getEncoded();

            //use it to sign the header and claimset
            local.signature = createObject("java", "java.security.Signature");
            local.keyFactory = createObject("java","java.security.KeyFactory");
            local.keySpec = createObject("java","java.security.spec.PKCS8EncodedKeySpec");

            local.signature = signature.getInstance("SHA256withRSA");
            local.signature.initSign(keyFactory.getInstance("RSA").generatePrivate(keySpec.init(local.privateKey)));
            local.jMsg = JavaCast("string",arguments.String).getBytes('utf-8');
            local.signature.update(local.jMsg);
            local.signBytes = local.signature.sign();

            return local.signBytes;
        }


        private string function Base64URLEncode(required string String ){
            return Replace( Replace( Replace( toBase64(Arguments.String), "=", "", "all"), "+", "-", "all"), "/", "_", "all");
        }

    }
    </cfscript>

0 个答案:

没有答案