EIOServiceImpl.java 7.52 KB
/*
 * Decompiled with CFR 0_118.
 * 
 * Could not load the following classes:
 *  com.adobe.granite.crypto.CryptoException
 *  com.adobe.granite.oauth.jwt.JwsBuilder
 *  com.adobe.granite.oauth.jwt.JwsBuilderFactory
 *  com.adobe.granite.oauth.jwt.JwsValidator
 *  javax.annotation.Nonnull
 *  javax.servlet.http.HttpServletRequest
 *  org.apache.felix.scr.annotations.Component
 *  org.apache.felix.scr.annotations.Deactivate
 *  org.apache.felix.scr.annotations.Reference
 *  org.apache.felix.scr.annotations.Service
 *  org.apache.oltu.oauth2.jwt.ClaimsSet
 *  org.apache.oltu.oauth2.jwt.JWT
 *  org.apache.oltu.oauth2.jwt.io.JWTReader
 *  org.slf4j.Logger
 *  org.slf4j.LoggerFactory
 */
package com.adobe.granite.socketio.impl.engine;

import com.adobe.granite.crypto.CryptoException;
import com.adobe.granite.oauth.jwt.JwsBuilder;
import com.adobe.granite.oauth.jwt.JwsBuilderFactory;
import com.adobe.granite.oauth.jwt.JwsValidator;
import com.adobe.granite.socketio.impl.engine.EIOListener;
import com.adobe.granite.socketio.impl.engine.EIOService;
import com.adobe.granite.socketio.impl.engine.EIOSocket;
import com.adobe.granite.socketio.impl.engine.EIOTransport;
import com.adobe.granite.socketio.impl.engine.EIOWebSocketTransport;
import java.io.IOException;
import java.security.Principal;
import java.util.Collection;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import javax.annotation.Nonnull;
import javax.servlet.http.HttpServletRequest;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Deactivate;
import org.apache.felix.scr.annotations.Reference;
import org.apache.felix.scr.annotations.Service;
import org.apache.oltu.oauth2.jwt.ClaimsSet;
import org.apache.oltu.oauth2.jwt.JWT;
import org.apache.oltu.oauth2.jwt.io.JWTReader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@Component
@Service
public class EIOServiceImpl
implements EIOService {
    private static final Logger log = LoggerFactory.getLogger(EIOServiceImpl.class);
    private final ConcurrentMap<EIOListener, Object> listeners = new ConcurrentHashMap<EIOListener, Object>();
    private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
    private final ConcurrentHashMap<String, EIOSocket> sockets = new ConcurrentHashMap();
    private long pingTimeout = 60000;
    private long pingInterval = 25000;
    private static long DEFAULT_TOKEN_EXPIRATION_TIME = 5000;
    @Reference
    private JwsBuilderFactory jwsBuilderFactory;
    @Reference
    private JwsValidator jwsValidator;

    @Deactivate
    private void deactivate() {
        for (EIOSocket socket : this.sockets.values()) {
            socket.close();
        }
    }

    protected ScheduledFuture<?> schedulePingTimeout(Runnable timeoutHandler) {
        return this.scheduler.schedule(timeoutHandler, this.pingTimeout + this.pingInterval, TimeUnit.MILLISECONDS);
    }

    protected void onConnect(EIOSocket socket) {
        for (EIOListener l : this.listeners.keySet()) {
            l.onConnect(socket);
        }
    }

    protected void onDisconnect(EIOSocket socket) {
        for (EIOListener l : this.listeners.keySet()) {
            l.onDisconnect(socket);
        }
        this.sockets.remove(socket.getId());
        log.debug("socket {} removed. size = {}", (Object)socket.getId(), (Object)this.sockets.size());
    }

    @Override
    public EIOSocket getSocket(String id) {
        return this.sockets.get(id);
    }

    @Override
    public EIOSocket createSocket(String id, String transport, Principal userPrincipal) {
        if (!this.isTransportSupported(transport)) {
            throw new IllegalArgumentException("Unsupported transport: " + transport);
        }
        if (id == null) {
            id = UUID.randomUUID().toString();
        }
        if (this.sockets.containsKey(id)) {
            throw new IllegalArgumentException("Socket already exists: " + id);
        }
        EIOWebSocketTransport tsp = new EIOWebSocketTransport(id);
        EIOSocket socket = new EIOSocket(id, this, tsp, userPrincipal);
        this.sockets.put(id, socket);
        log.debug("socket {} created. size = {}", (Object)id, (Object)this.sockets.size());
        return socket;
    }

    @Override
    public boolean isTransportSupported(String transport) {
        return "websocket".equals(transport);
    }

    @Override
    public long getPingTimeout() {
        return this.pingTimeout;
    }

    @Override
    public long getPingInterval() {
        return this.pingInterval;
    }

    @Override
    public void register(EIOListener listener) {
        this.listeners.put(listener, listener);
    }

    @Override
    public void unregister(EIOListener listener) {
        this.listeners.remove(listener);
    }

    @Override
    public String createSessionToken(@Nonnull HttpServletRequest req) throws IOException {
        try {
            String user = req.getUserPrincipal() == null ? null : req.getUserPrincipal().getName();
            String token = this.jwsBuilderFactory.getInstance("HS256").setIssuer(user).setExpiresIn(DEFAULT_TOKEN_EXPIRATION_TIME).setCustomClaimsSetField("jti", (Object)UUID.randomUUID().toString()).build();
            log.debug("Created new JWT token: {}", (Object)token);
            return token;
        }
        catch (CryptoException e) {
            log.error("Error while creating JWT token", (Throwable)e);
            throw new IOException((Throwable)e);
        }
    }

    @Override
    public String validateToken(String token, HttpServletRequest req) {
        if (!this.jwsValidator.validate(token)) {
            log.info("provided token not valid: {}", (Object)token);
            return null;
        }
        JWT t = (JWT)new JWTReader().read(token);
        log.debug("received valid token: {}", (Object)t);
        if (t.getClaimsSet().getExpirationTime() > System.currentTimeMillis()) {
            log.info("provided token expired: {}", (Object)token);
            return null;
        }
        String user = req.getUserPrincipal() == null ? "" : req.getUserPrincipal().getName();
        String issuer = t.getClaimsSet().getIssuer();
        if (issuer == null) {
            issuer = "";
        }
        if (!user.equals(issuer)) {
            log.info("provided token user mismatch: {} != {}", (Object)user, (Object)issuer);
            return null;
        }
        String sid = t.getClaimsSet().getJwdId();
        if (sid == null) {
            log.info("provided token has no session id: {}", (Object)token);
            return null;
        }
        if (this.sockets.containsKey(sid)) {
            log.warn("provided session id ({}) in jwt token already in use: {}", (Object)sid, (Object)token);
            return null;
        }
        return sid;
    }

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

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

    protected void bindJwsValidator(JwsValidator jwsValidator) {
        this.jwsValidator = jwsValidator;
    }

    protected void unbindJwsValidator(JwsValidator jwsValidator) {
        if (this.jwsValidator == jwsValidator) {
            this.jwsValidator = null;
        }
    }
}