X-Git-Url: https://juplo.de/gitweb/?a=blobdiff_plain;ds=sidebyside;f=dist%2Ffacebook-utils-2.5.0%2Fxref%2Fde%2Fjuplo%2Ffacebook%2Ftoken%2FSignedRequestAwareAuthorizationCodeAccessTokenProvider.html;fp=dist%2Ffacebook-utils-2.5.0%2Fxref%2Fde%2Fjuplo%2Ffacebook%2Ftoken%2FSignedRequestAwareAuthorizationCodeAccessTokenProvider.html;h=5b65226f186e565f4f093b35282b3c765c438712;hb=a53595184bd6e57bdc45292cc92c393c4e2dfe6e;hp=0000000000000000000000000000000000000000;hpb=c48c9ee0e9faa89a4c0a5323b367b9f5a6abe602;p=website diff --git a/dist/facebook-utils-2.5.0/xref/de/juplo/facebook/token/SignedRequestAwareAuthorizationCodeAccessTokenProvider.html b/dist/facebook-utils-2.5.0/xref/de/juplo/facebook/token/SignedRequestAwareAuthorizationCodeAccessTokenProvider.html new file mode 100644 index 00000000..5b65226f --- /dev/null +++ b/dist/facebook-utils-2.5.0/xref/de/juplo/facebook/token/SignedRequestAwareAuthorizationCodeAccessTokenProvider.html @@ -0,0 +1,261 @@ + + + +SignedRequestAwareAuthorizationCodeAccessTokenProvider xref + + + +
View Javadoc
+1   package de.juplo.facebook.token;
+2   
+3   
+4   import java.io.IOException;
+5   import java.io.UnsupportedEncodingException;
+6   import java.security.InvalidKeyException;
+7   import java.security.NoSuchAlgorithmException;
+8   import java.util.Date;
+9   import java.util.HashMap;
+10  import java.util.Map;
+11  import java.util.regex.Matcher;
+12  import java.util.regex.Pattern;
+13  import javax.crypto.Mac;
+14  import javax.crypto.spec.SecretKeySpec;
+15  import org.apache.commons.codec.binary.Base64;
+16  import org.codehaus.jackson.JsonNode;
+17  import org.codehaus.jackson.map.ObjectMapper;
+18  import org.slf4j.Logger;
+19  import org.slf4j.LoggerFactory;
+20  import org.springframework.security.oauth2.client.resource.OAuth2ProtectedResourceDetails;
+21  import org.springframework.security.oauth2.client.resource.UserRedirectRequiredException;
+22  import org.springframework.security.oauth2.client.token.AccessTokenRequest;
+23  import org.springframework.security.oauth2.client.token.grant.code.AuthorizationCodeAccessTokenProvider;
+24  import org.springframework.security.oauth2.common.DefaultOAuth2AccessToken;
+25  import org.springframework.security.oauth2.common.OAuth2AccessToken;
+26  
+27  
+28  /**
+29   * This class extends {@link AuthorizationCodeAccessTokenProvider} and adds
+30   * support for signed requests, which are issued by Facebook, if the Canvas-
+31   * or Tab-Page of a Facebook-App is accessed for the first time.
+32   *
+33   * @author Kai Moritz
+34   */
+35  public class SignedRequestAwareAuthorizationCodeAccessTokenProvider
+36      extends AuthorizationCodeAccessTokenProvider
+37  {
+38    private final Logger log =
+39        LoggerFactory.getLogger(SignedRequestAwareAuthorizationCodeAccessTokenProvider.class);
+40    private final static Pattern pattern =
+41        Pattern.compile("([a-zA-Z0-9_-]+)\\.([a-zA-Z0-9_-]+)");
+42  
+43    public final static String PARAM_SIGNED_REQUEST = "signed_request";
+44  
+45  
+46    private String secret;
+47    private ObjectMapper objectMapper;
+48  
+49  
+50    @Override
+51    public OAuth2AccessToken obtainAccessToken(
+52        OAuth2ProtectedResourceDetails details,
+53        AccessTokenRequest parameters
+54        )
+55    {
+56      try
+57      {
+58        return super.obtainAccessToken(details, parameters);
+59      }
+60      catch (UserRedirectRequiredException redirect)
+61      {
+62        log.debug("no valid access-token available: checking for signed request");
+63  
+64        if (!parameters.containsKey(PARAM_SIGNED_REQUEST))
+65        {
+66          log.info(
+67              "parameter " + PARAM_SIGNED_REQUEST + " is not present"
+68              );
+69          throw redirect;
+70        }
+71  
+72        String signed_request = parameters.get(PARAM_SIGNED_REQUEST).get(0);
+73  
+74        Matcher matcher = pattern.matcher(signed_request);
+75        if (!matcher.matches())
+76        {
+77          log.error("invalid signed_request: {}", signed_request);
+78          throw redirect;
+79        }
+80  
+81        String signature = matcher.group(1);
+82        String rawdata = matcher.group(2);
+83  
+84        String data;
+85        try
+86        {
+87          data = new String(Base64.decodeBase64(rawdata), "UTF-8");
+88          log.debug("JSON-data: {}", data);
+89        }
+90        catch (UnsupportedEncodingException e)
+91        {
+92          log.error("error while decoding data: {}", e.getMessage());
+93          throw redirect;
+94        }
+95  
+96        JsonNode json;
+97        try
+98        {
+99          json = objectMapper.readTree(data);
+100       }
+101       catch (IOException e)
+102       {
+103         log.error("error \"{}\" while parsing JSON-data: {}", e, data);
+104         throw redirect;
+105       }
+106 
+107       String algorithm = "";
+108       try
+109       {
+110         algorithm = json.get("algorithm").asText();
+111       }
+112       catch (NullPointerException e) {}
+113       if (algorithm.isEmpty())
+114       {
+115         log.error("field \"algorithm\" is missing: {}", data);
+116         throw redirect;
+117       }
+118       algorithm = algorithm.replaceAll("-", "");
+119 
+120       String check;
+121       try
+122       {
+123         SecretKeySpec key = new SecretKeySpec(secret.getBytes("UTF-8"), algorithm);
+124         Mac mac = Mac.getInstance(algorithm);
+125         mac.init(key);
+126         byte[] hmacData = mac.doFinal(rawdata.getBytes("UTF-8"));
+127         check = new String(Base64.encodeBase64URLSafe(hmacData), "UTF-8");
+128       }
+129       catch (
+130           UnsupportedEncodingException |
+131           NoSuchAlgorithmException |
+132           InvalidKeyException |
+133           IllegalStateException e
+134           )
+135       {
+136         log.error("signature check failed!", e);
+137         throw redirect;
+138       }
+139       if (!check.equals(signature))
+140       {
+141         log.error("signature does not match!");
+142         throw redirect;
+143       }
+144 
+145       /**
+146        * Extract additional information and store it in the token
+147        * See:
+148        * https://developers.facebook.com/docs/reference/login/signed-request/
+149        * TODO:
+150        * - Attribute "code"
+151        */
+152       Map<String,Object> additionalInformation = new HashMap<>();
+153       try
+154       {
+155         additionalInformation.put(
+156             "issued_at",
+157             new Date(json.get("issued_at").getLongValue()*1000L)
+158             );
+159         Map<String,Object> user = new HashMap<>();
+160         user.put(
+161             "country",
+162             json.get("user").get("country").asText()
+163             );
+164         user.put(
+165             "locale",
+166             json.get("user").get("locale").asText()
+167             );
+168         user.put(
+169             "age_min",
+170             json.get("user").get("age").get("min").getNumberValue()
+171             );
+172         if (json.get("user") != null && json.get("user").get("max") != null)
+173           user.put(
+174               "age_max",
+175               json.get("user").get("age").get("max").getNumberValue()
+176               );
+177         additionalInformation.put("user", user);
+178         if (json.get("app_data") != null)
+179           additionalInformation.put("app_data", json.get("app_data").asText());
+180         if (json.get("page") != null)
+181         {
+182           Map<String,Object> page = new HashMap<>();
+183           page.put("id", json.get("page").get("id").asText());
+184           page.put("liked", json.get("page").get("liked").asBoolean());
+185           page.put("admin", json.get("page").get("admin").asBoolean());
+186           additionalInformation.put("page", page);
+187         }
+188       }
+189       catch (NullPointerException e)
+190       {
+191         log.warn("expected additional data is missing: {}", data);
+192       }
+193 
+194       DefaultOAuth2AccessToken token = null;
+195       try
+196       {
+197         String value = json.get("oauth_token").asText();
+198         if (value.isEmpty())
+199         {
+200           log.error("field \"oauth_token\" is missing: {}", data);
+201           throw redirect;
+202         }
+203         token = new DefaultOAuth2AccessToken(value);
+204         token.setExpiration(new Date(json.get("expires").getLongValue()*1000L));
+205 
+206         additionalInformation.put(
+207             "user_id",
+208             json.get("user_id").asText()
+209             );
+210 
+211         token.setAdditionalInformation(additionalInformation);
+212       }
+213       catch (NullPointerException e)
+214       {
+215         if (token == null)
+216         {
+217           log.error("field \"oauth_token\" is missing: {}", data);
+218           throw redirect;
+219         }
+220         else
+221           log.warn("expected additional data is missing: {}", data);
+222       }
+223 
+224       return token;
+225     }
+226   }
+227 
+228 
+229   public String getSecret()
+230   {
+231     return secret;
+232   }
+233 
+234   public void setSecret(String secret)
+235   {
+236     this.secret = secret;
+237   }
+238 
+239   public ObjectMapper getObjectMapper()
+240   {
+241     return objectMapper;
+242   }
+243 
+244   public void setObjectMapper(ObjectMapper objectMapper)
+245   {
+246     this.objectMapper = objectMapper;
+247   }
+248 }
+
+
+ + +