X-Git-Url: https://juplo.de/gitweb/?p=facebook-errors;a=blobdiff_plain;f=src%2Fmain%2Fjava%2Fde%2Fjuplo%2Ffacebook%2FSignedRequestAwareAuthorizationCodeAccessTokenProvider.java;fp=src%2Fmain%2Fjava%2Fde%2Fjuplo%2Ffacebook%2FSignedRequestAwareAuthorizationCodeAccessTokenProvider.java;h=0000000000000000000000000000000000000000;hp=fcae74adb7180e7a3a3cc16d0407b82e5564ab4b;hb=bc0989ddb7bb05e2d95ae4aad4438b4d4806f9dc;hpb=80f6b663c648f011425b521e7c4185128a00149d diff --git a/src/main/java/de/juplo/facebook/SignedRequestAwareAuthorizationCodeAccessTokenProvider.java b/src/main/java/de/juplo/facebook/SignedRequestAwareAuthorizationCodeAccessTokenProvider.java deleted file mode 100644 index fcae74a..0000000 --- a/src/main/java/de/juplo/facebook/SignedRequestAwareAuthorizationCodeAccessTokenProvider.java +++ /dev/null @@ -1,248 +0,0 @@ -package de.juplo.facebook; - - -import java.io.IOException; -import java.io.UnsupportedEncodingException; -import java.security.InvalidKeyException; -import java.security.NoSuchAlgorithmException; -import java.util.Date; -import java.util.HashMap; -import java.util.Map; -import java.util.regex.Matcher; -import java.util.regex.Pattern; -import javax.crypto.Mac; -import javax.crypto.spec.SecretKeySpec; -import org.apache.commons.codec.binary.Base64; -import org.codehaus.jackson.JsonNode; -import org.codehaus.jackson.map.ObjectMapper; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.security.oauth2.client.resource.OAuth2ProtectedResourceDetails; -import org.springframework.security.oauth2.client.resource.UserRedirectRequiredException; -import org.springframework.security.oauth2.client.token.AccessTokenRequest; -import org.springframework.security.oauth2.client.token.grant.code.AuthorizationCodeAccessTokenProvider; -import org.springframework.security.oauth2.common.DefaultOAuth2AccessToken; -import org.springframework.security.oauth2.common.OAuth2AccessToken; - - -/** - * This class extends {@link AuthorizationCodeAccessTokenProvider} and adds - * support for signed requests, which are issued by Facebook, if the Canvas- - * or Tab-Page of a Facebook-App is accessed for the first time. - * - * @author Kai Moritz - */ -public class SignedRequestAwareAuthorizationCodeAccessTokenProvider - extends AuthorizationCodeAccessTokenProvider -{ - private final Logger log = - LoggerFactory.getLogger(SignedRequestAwareAuthorizationCodeAccessTokenProvider.class); - private final static Pattern pattern = - Pattern.compile("([a-zA-Z0-9_-]+)\\.([a-zA-Z0-9_-]+)"); - - public final static String PARAM_SIGNED_REQUEST = "signed_request"; - - - private String secret; - private ObjectMapper objectMapper; - - - @Override - public OAuth2AccessToken obtainAccessToken( - OAuth2ProtectedResourceDetails details, - AccessTokenRequest parameters - ) - { - try - { - return super.obtainAccessToken(details, parameters); - } - catch (UserRedirectRequiredException redirect) - { - log.debug("no valid access-token available: checking for signed request"); - - if (!parameters.containsKey(PARAM_SIGNED_REQUEST)) - { - log.info( - "parameter " + PARAM_SIGNED_REQUEST + " is not present" - ); - throw redirect; - } - - String signed_request = parameters.get(PARAM_SIGNED_REQUEST).get(0); - - Matcher matcher = pattern.matcher(signed_request); - if (!matcher.matches()) - { - log.error("invalid signed_request: {}", signed_request); - throw redirect; - } - - String signature = matcher.group(1); - String rawdata = matcher.group(2); - - String data; - try - { - data = new String(Base64.decodeBase64(rawdata), "UTF-8"); - log.debug("JSON-data: {}", data); - } - catch (UnsupportedEncodingException e) - { - log.error("error while decoding data: {}", e.getMessage()); - throw redirect; - } - - JsonNode json; - try - { - json = objectMapper.readTree(data); - } - catch (IOException e) - { - log.error("error \"{}\" while parsing JSON-data: {}", e, data); - throw redirect; - } - - String algorithm = ""; - try - { - algorithm = json.get("algorithm").asText(); - } - catch (NullPointerException e) {} - if (algorithm.isEmpty()) - { - log.error("field \"algorithm\" is missing: {}", data); - throw redirect; - } - algorithm = algorithm.replaceAll("-", ""); - - String check; - try - { - SecretKeySpec key = new SecretKeySpec(secret.getBytes("UTF-8"), algorithm); - Mac mac = Mac.getInstance(algorithm); - mac.init(key); - byte[] hmacData = mac.doFinal(rawdata.getBytes("UTF-8")); - check = new String(Base64.encodeBase64URLSafe(hmacData), "UTF-8"); - } - catch ( - UnsupportedEncodingException | - NoSuchAlgorithmException | - InvalidKeyException | - IllegalStateException e - ) - { - log.error("signature check failed!", e); - throw redirect; - } - if (!check.equals(signature)) - { - log.error("signature does not match!"); - throw redirect; - } - - /** - * Extract additional information and store it in the token - * See: - * https://developers.facebook.com/docs/reference/login/signed-request/ - * TODO: - * - Attribute "code" - */ - Map additionalInformation = new HashMap<>(); - try - { - additionalInformation.put( - "issued_at", - new Date(json.get("issued_at").getLongValue()*1000L) - ); - Map user = new HashMap<>(); - user.put( - "country", - json.get("user").get("country").asText() - ); - user.put( - "locale", - json.get("user").get("locale").asText() - ); - user.put( - "age_min", - json.get("user").get("age").get("min").getNumberValue() - ); - if (json.get("user") != null && json.get("user").get("max") != null) - user.put( - "age_max", - json.get("user").get("age").get("max").getNumberValue() - ); - additionalInformation.put("user", user); - if (json.get("app_data") != null) - additionalInformation.put("app_data", json.get("app_data").asText()); - if (json.get("page") != null) - { - Map page = new HashMap<>(); - page.put("id", json.get("page").get("id").asText()); - page.put("liked", json.get("page").get("liked").asBoolean()); - page.put("admin", json.get("page").get("admin").asBoolean()); - additionalInformation.put("page", page); - } - } - catch (NullPointerException e) - { - log.warn("expected additional data is missing: {}", data); - } - - DefaultOAuth2AccessToken token = null; - try - { - String value = json.get("oauth_token").asText(); - if (value.isEmpty()) - { - log.error("field \"oauth_token\" is missing: {}", data); - throw redirect; - } - token = new DefaultOAuth2AccessToken(value); - token.setExpiration(new Date(json.get("expires").getLongValue()*1000L)); - - additionalInformation.put( - "user_id", - json.get("user_id").asText() - ); - - token.setAdditionalInformation(additionalInformation); - } - catch (NullPointerException e) - { - if (token == null) - { - log.error("field \"oauth_token\" is missing: {}", data); - throw redirect; - } - else - log.warn("expected additional data is missing: {}", data); - } - - return token; - } - } - - - public String getSecret() - { - return secret; - } - - public void setSecret(String secret) - { - this.secret = secret; - } - - public ObjectMapper getObjectMapper() - { - return objectMapper; - } - - public void setObjectMapper(ObjectMapper objectMapper) - { - this.objectMapper = objectMapper; - } -}