TicketServiceImpl.java 8.05 KB
/*
 * Decompiled with CFR 0_118.
 * 
 * Could not load the following classes:
 *  com.adobe.granite.crypto.CryptoException
 *  com.adobe.granite.crypto.CryptoSupport
 *  javax.jcr.RepositoryException
 *  org.apache.commons.codec.binary.Base64
 *  org.apache.felix.scr.annotations.Activate
 *  org.apache.felix.scr.annotations.Component
 *  org.apache.felix.scr.annotations.Deactivate
 *  org.apache.felix.scr.annotations.Property
 *  org.apache.felix.scr.annotations.Reference
 *  org.apache.felix.scr.annotations.Service
 *  org.apache.sling.commons.osgi.OsgiUtil
 *  org.apache.sling.jcr.api.SlingRepository
 *  org.slf4j.Logger
 *  org.slf4j.LoggerFactory
 */
package com.adobe.aemds.core.ticketservice.impl;

import com.adobe.aemds.core.ticketservice.api.AuthTicket;
import com.adobe.aemds.core.ticketservice.api.InvalidTicketException;
import com.adobe.aemds.core.ticketservice.api.TicketOptions;
import com.adobe.aemds.core.ticketservice.api.TicketService;
import com.adobe.granite.crypto.CryptoException;
import com.adobe.granite.crypto.CryptoSupport;
import java.util.GregorianCalendar;
import java.util.Map;
import javax.jcr.RepositoryException;
import org.apache.commons.codec.binary.Base64;
import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Deactivate;
import org.apache.felix.scr.annotations.Property;
import org.apache.felix.scr.annotations.Reference;
import org.apache.felix.scr.annotations.Service;
import org.apache.sling.commons.osgi.OsgiUtil;
import org.apache.sling.jcr.api.SlingRepository;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/*
 * This class specifies class file version 49.0 but uses Java 6 signatures.  Assumed Java 6.
 */
@Component(metatype=1, immediate=1, label="%auth.ticket.name", description="%auth.ticket.description")
@Service(value={TicketService.class})
public class TicketServiceImpl
implements TicketService {
    private static final Logger log = LoggerFactory.getLogger(TicketServiceImpl.class);
    private static final int DEFAULT_TICKET_VALIDITY_DURATION = 600;
    private static final String DELIM = ":";
    @Property(intValue={600})
    private static final String PROP_TICKET_VALIDITY_DURATION = "ticket.validity.seconds";
    @Reference
    CryptoSupport cryptoSupport;
    @Reference
    SlingRepository slingRepository;
    private int ticketValidityPeriod = 600;

    @Activate
    private void activate(Map<String, Object> config) {
        this.ticketValidityPeriod = OsgiUtil.toInteger((Object)config.get("ticket.validity.seconds"), (int)600);
        if (this.ticketValidityPeriod < 1) {
            throw new IllegalArgumentException("ticket.validity.seconds = " + this.ticketValidityPeriod + ". Negative value not allowed");
        }
        log.debug("Activated AEM DS Ticket Service with configuration { ticketValidityPeriod : {}}", (Object)this.ticketValidityPeriod);
    }

    @Deactivate
    private void deactivate() {
        if (this.cryptoSupport != null) {
            this.cryptoSupport = null;
        }
        log.debug("Deactivated AEM DS Ticket Service");
    }

    @Override
    public AuthTicket issueTicket(String principalName, TicketOptions options) {
        try {
            if (options == null) {
                options = new TicketOptions();
            }
            return this.issueTicket0(principalName, options);
        }
        catch (CryptoException e) {
            log.debug("Failed to issue ticket for principal : " + principalName, (Throwable)e);
        }
        catch (RepositoryException e) {
            log.debug("Failed to issue ticket for principal : " + principalName, (Throwable)e);
        }
        return null;
    }

    @Override
    public AuthTicket verifyTicket(String ticketValue) throws InvalidTicketException {
        try {
            if (ticketValue == null) {
                throw new InvalidTicketException("Ticket value passed is empty");
            }
            return this.verifyTicket0(ticketValue);
        }
        catch (CryptoException e) {
            throw new InvalidTicketException("Ticket not valid", (Throwable)e);
        }
        catch (NumberFormatException e) {
            throw new InvalidTicketException("Ticket not valid. Timestamp cannot be parsed to number.", e);
        }
        catch (RuntimeException re) {
            throw new InvalidTicketException("Ticket not valid", re);
        }
    }

    private String[] splitOnLast(String str) {
        int idx = str.lastIndexOf(":");
        String v0 = str.substring(0, idx);
        String v1 = str.substring(idx + ":".length());
        return new String[]{v0, v1};
    }

    private AuthTicket verifyTicket0(String ticketValue) throws CryptoException, NumberFormatException, InvalidTicketException {
        String unProtectedValue = this.cryptoSupport.unprotect(new String(Base64.decodeBase64((String)ticketValue)));
        log.debug("Verifying Ticket : {}", (Object)unProtectedValue);
        if (unProtectedValue == null) {
            throw new InvalidTicketException("Ticket not Valid : ");
        }
        String[] s1 = this.splitOnLast(unProtectedValue);
        long endTimeStamp = Long.valueOf(s1[1]);
        String[] s2 = this.splitOnLast(s1[0]);
        long startTimeStamp = Long.valueOf(s2[1]);
        String principalName = s2[0];
        long currentTime = GregorianCalendar.getInstance().getTimeInMillis();
        if (startTimeStamp <= currentTime && endTimeStamp >= currentTime) {
            AuthTicket tkt = new AuthTicket();
            tkt.setPrincipalName(principalName);
            log.debug("Successfully verified ticket : {}", (Object)tkt);
            return tkt;
        }
        throw new InvalidTicketException("Ticket has expired");
    }

    private AuthTicket issueTicket0(String principalName, TicketOptions options) throws CryptoException, RepositoryException {
        if (principalName == null || principalName.isEmpty()) {
            throw new IllegalArgumentException("principalName should not be null or empty");
        }
        int validityPeriod = this.getTicketValidityPeriod(options);
        long startTimeStamp = GregorianCalendar.getInstance().getTimeInMillis();
        long endTimestamp = startTimeStamp + (long)(validityPeriod * 1000);
        String ticketValue = this.generateTicket(principalName, startTimeStamp, endTimestamp);
        if (log.isDebugEnabled()) {
            log.debug("Issued ticket for principal :[{}] , Start Time : [{}] , Expiry Time : [{}] ", new Object[]{principalName, startTimeStamp, endTimestamp});
        }
        return new AuthTicket(principalName, ticketValue);
    }

    private int getTicketValidityPeriod(TicketOptions options) {
        int validityPeriod = options.getDuration();
        if (validityPeriod == -1 || validityPeriod > this.ticketValidityPeriod) {
            log.debug("Ticket duration requested =  [{}]. Max duration allowed =  [{}]. Using max duration for ticket creation", new Object[]{validityPeriod, this.ticketValidityPeriod});
            validityPeriod = this.ticketValidityPeriod;
        }
        if (validityPeriod < 0) {
            throw new IllegalArgumentException("Ticket validity duration cannot be negative. Value found = " + validityPeriod);
        }
        return validityPeriod;
    }

    private String generateTicket(String principalName, long startTimestamp, long endTimestamp) throws CryptoException {
        return Base64.encodeBase64String((byte[])this.cryptoSupport.protect(principalName + ":" + startTimestamp + ":" + endTimestamp).getBytes());
    }

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

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

    protected void bindSlingRepository(SlingRepository slingRepository) {
        this.slingRepository = slingRepository;
    }

    protected void unbindSlingRepository(SlingRepository slingRepository) {
        if (this.slingRepository == slingRepository) {
            this.slingRepository = null;
        }
    }
}