keywhiz.auth.cookie.AuthenticatedEncryptedCookieFactory.java Source code

Java tutorial

Introduction

Here is the source code for keywhiz.auth.cookie.AuthenticatedEncryptedCookieFactory.java

Source

/*
 * Copyright (C) 2015 Square, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package keywhiz.auth.cookie;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.base.Throwables;
import java.time.Clock;
import java.time.Duration;
import java.time.ZonedDateTime;
import java.util.Base64;
import javax.crypto.AEADBadTagException;
import javax.inject.Inject;
import javax.ws.rs.core.NewCookie;
import keywhiz.auth.User;
import org.eclipse.jetty.http.HttpCookie;
import org.eclipse.jetty.http.HttpHeader;
import org.eclipse.jetty.server.Response;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import static java.nio.charset.StandardCharsets.UTF_8;

/** Produces tokens and cookies based on encrypted {@link UserCookieData} records. */
public class AuthenticatedEncryptedCookieFactory {
    private static final Logger logger = LoggerFactory.getLogger(AuthenticatedEncryptedCookieFactory.class);

    private final Clock clock;
    private final ObjectMapper mapper;
    private final GCMEncryptor encryptor;
    private final CookieConfig config;

    /**
     * @param clock to use for resolving current time
     * @param mapper json serializer
     * @param encryptor performs authenticated-encryption using a non-colliding counter specific to a host.
     * @param config parameters for cookie generation
     */
    @Inject
    public AuthenticatedEncryptedCookieFactory(Clock clock, ObjectMapper mapper, GCMEncryptor encryptor,
            @SessionCookie CookieConfig config) {
        this.clock = clock;
        this.mapper = mapper;
        this.encryptor = encryptor;
        this.config = config;
    }

    /**
     * Produces an authenticating token.
     *
     * @param user identity the token will authenticate.
     * @param expiration timestamp when token should expire.
     * @return token which can be used to authenticate as user until expiration.
     */
    public String getSession(User user, ZonedDateTime expiration) {
        try {
            String cookieJson = mapper.writeValueAsString(new UserCookieData(user, expiration));
            byte[] cookieBody = encryptor.encrypt(cookieJson.getBytes(UTF_8));
            return Base64.getEncoder().encodeToString(cookieBody);
        } catch (AEADBadTagException e) {
            logger.error("Could not encrypt cookie", e);
            throw Throwables.propagate(e);
        } catch (JsonProcessingException e) {
            throw Throwables.propagate(e);
        }
    }

    /**
     * Produces a cookie string for a given value and expiration.
     *
     * @param value value of new cookie.
     * @param expiration expiration time of cookie.
     * @return serialized cookie with given value and expiration.
     */
    public NewCookie cookieFor(String value, ZonedDateTime expiration) {
        long maxAge = Duration.between(ZonedDateTime.now(clock), expiration).getSeconds();

        HttpCookie cookie = new HttpCookie(config.getName(), value, config.getDomain(), config.getPath(), maxAge,
                config.isHttpOnly(), config.isSecure());

        Response response = new Response(null, null);
        response.addCookie(cookie);
        return NewCookie.valueOf(response.getHttpFields().getStringField(HttpHeader.SET_COOKIE));
    }

    /**
     * Shortcut method to produce an authenticated cookie string.
     *
     * @param user identity the token will authenticate.
     * @param expiration timestamp when cookie should expire.
     * @return serialized cookie which can be used to authenticate as user until expiration.
     */
    public NewCookie getSessionCookie(User user, ZonedDateTime expiration) {
        return cookieFor(getSession(user, expiration), expiration);
    }

    /**
     * Produces an expired cookie string, used to update/overwrite an existing cookie.
     *
     * @return serialized expired cookie with matching parameters to authenticating cookie.
     */
    public NewCookie getExpiredSessionCookie() {
        HttpCookie cookie = new HttpCookie(config.getName(), "expired", config.getDomain(), config.getPath(), 0,
                config.isHttpOnly(), config.isSecure());

        Response response = new Response(null, null);
        response.addCookie(cookie);
        return NewCookie.valueOf(response.getHttpFields().getStringField(HttpHeader.SET_COOKIE));
    }
}