CSRFServlet.java 6.14 KB
/*
 * Decompiled with CFR 0_118.
 * 
 * Could not load the following classes:
 *  com.adobe.granite.crypto.CryptoException
 *  com.adobe.granite.crypto.CryptoSupport
 *  com.adobe.granite.oauth.jwt.JwsBuilder
 *  com.adobe.granite.oauth.jwt.JwsBuilderFactory
 *  javax.servlet.ServletException
 *  org.apache.felix.scr.annotations.Activate
 *  org.apache.felix.scr.annotations.Modified
 *  org.apache.felix.scr.annotations.Property
 *  org.apache.felix.scr.annotations.Reference
 *  org.apache.felix.scr.annotations.sling.SlingServlet
 *  org.apache.oltu.commons.encodedtoken.TokenDecoder
 *  org.apache.oltu.commons.json.CustomizableEntity
 *  org.apache.oltu.oauth2.jwt.ClaimsSet
 *  org.apache.oltu.oauth2.jwt.JWT
 *  org.apache.oltu.oauth2.jwt.JWT$Builder
 *  org.apache.oltu.oauth2.jwt.io.JWTClaimsSetWriter
 *  org.apache.oltu.oauth2.jwt.io.JWTReader
 *  org.apache.sling.api.SlingHttpServletRequest
 *  org.apache.sling.api.SlingHttpServletResponse
 *  org.apache.sling.api.servlets.SlingSafeMethodsServlet
 *  org.apache.sling.commons.osgi.PropertiesUtil
 *  org.json.JSONWriter
 *  org.osgi.framework.BundleContext
 *  org.slf4j.Logger
 *  org.slf4j.LoggerFactory
 */
package com.adobe.granite.csrf.impl;

import com.adobe.granite.crypto.CryptoException;
import com.adobe.granite.crypto.CryptoSupport;
import com.adobe.granite.oauth.jwt.JwsBuilder;
import com.adobe.granite.oauth.jwt.JwsBuilderFactory;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.Writer;
import java.util.Map;
import javax.servlet.ServletException;
import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.Modified;
import org.apache.felix.scr.annotations.Property;
import org.apache.felix.scr.annotations.Reference;
import org.apache.felix.scr.annotations.sling.SlingServlet;
import org.apache.oltu.commons.encodedtoken.TokenDecoder;
import org.apache.oltu.commons.json.CustomizableEntity;
import org.apache.oltu.oauth2.jwt.ClaimsSet;
import org.apache.oltu.oauth2.jwt.JWT;
import org.apache.oltu.oauth2.jwt.io.JWTClaimsSetWriter;
import org.apache.oltu.oauth2.jwt.io.JWTReader;
import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.SlingHttpServletResponse;
import org.apache.sling.api.servlets.SlingSafeMethodsServlet;
import org.apache.sling.commons.osgi.PropertiesUtil;
import org.json.JSONWriter;
import org.osgi.framework.BundleContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/*
 * This class specifies class file version 49.0 but uses Java 6 signatures.  Assumed Java 6.
 */
@SlingServlet(resourceTypes={"granite/csrf/token"}, extensions={"json"}, metatype=1, description="Servlet that return the CSRF token for a given user.", label="Adobe Granite CSRF Servlet")
@Property(label="CSRF Token Expires In", description="The lifetime in seconds of the csrf token (min 600 seconds/10 minutes)", name="csrf.token.expires.in", longValue={600})
public class CSRFServlet
extends SlingSafeMethodsServlet {
    private static final long serialVersionUID = 1;
    static final long CSRF_TOKEN_EXPIRES_IN_DEFAULT = 600;
    private final Logger logger = LoggerFactory.getLogger(CSRFServlet.class);
    @Reference
    private JwsBuilderFactory jwsBuilderFactory;
    @Reference
    private CryptoSupport cryptoSupport;
    private long csrfTokenExpiresIn;

    @Activate
    @Modified
    private void activate(BundleContext context, Map<String, Object> config) {
        this.csrfTokenExpiresIn = PropertiesUtil.toLong((Object)config.get("csrf.token.expires.in"), (long)600);
        if (this.csrfTokenExpiresIn < 600) {
            this.logger.warn("The lifetime in seconds of the csrf token must be minimum 600 seconds/10 minutes, defaulting lifetime to 600 seconds/10 minutes");
            this.csrfTokenExpiresIn = 600;
        }
    }

    protected void doGet(SlingHttpServletRequest request, SlingHttpServletResponse response) throws ServletException, IOException {
        JSONWriter writer = new JSONWriter((Writer)response.getWriter());
        writer.object();
        try {
            if (request.getAuthType() != null) {
                String user = request.getRemoteUser();
                String csrfToken = this.getCSRFToken(user);
                writer.key("token").value((Object)csrfToken);
            } else {
                this.logger.debug("doGet: CSRF token available only for authenticated users");
            }
            response.setContentType("application/json");
            response.setCharacterEncoding("utf8");
            response.setHeader("Cache-Control", "no-cache");
            response.setStatus(200);
            writer.endObject();
        }
        catch (CryptoException e) {
            this.logger.error("doGet: failed to generate CSRF token", (Throwable)e);
            response.sendError(500);
        }
    }

    private String getCSRFToken(String user) throws NumberFormatException, CryptoException {
        StringBuilder sb = new StringBuilder();
        String token = this.jwsBuilderFactory.getInstance("HS256").setSubject(user).setExpiresIn(this.csrfTokenExpiresIn).setCustomClaimsSetField("scope", (Object)":aem_csrf_token_value").build();
        JWT jws = (JWT)new JWTReader().read(token);
        long iat = jws.getClaimsSet().getIssuedAt();
        JWT jwt = new JWT.Builder().setClaimsSetIssuedAt(iat).setClaimsSetExpirationTime(iat + this.csrfTokenExpiresIn).build();
        String payload = new JWTClaimsSetWriter().write((CustomizableEntity)jwt.getClaimsSet());
        sb.append(TokenDecoder.base64Encode((String)payload)).append(".").append(jws.getSignature());
        return sb.toString();
    }

    protected void bindJwsBuilderFactory(JwsBuilderFactory jwsBuilderFactory) {
        this.jwsBuilderFactory = jwsBuilderFactory;
    }

    protected void unbindJwsBuilderFactory(JwsBuilderFactory jwsBuilderFactory) {
        if (this.jwsBuilderFactory == jwsBuilderFactory) {
            this.jwsBuilderFactory = null;
        }
    }

    protected void bindCryptoSupport(CryptoSupport cryptoSupport) {
        this.cryptoSupport = cryptoSupport;
    }

    protected void unbindCryptoSupport(CryptoSupport cryptoSupport) {
        if (this.cryptoSupport == cryptoSupport) {
            this.cryptoSupport = null;
        }
    }
}