/*
* Copyright © 2014 Cask Data, 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 co.cask.cdap.security.server;
import co.cask.cdap.common.conf.CConfiguration;
import co.cask.cdap.common.conf.Constants;
import co.cask.cdap.common.io.Codec;
import co.cask.cdap.security.auth.AccessToken;
import co.cask.cdap.security.auth.AccessTokenIdentifier;
import co.cask.cdap.security.auth.TokenManager;
import com.google.common.base.Charsets;
import com.google.gson.JsonObject;
import com.google.inject.Inject;
import org.apache.commons.codec.binary.Base64;
import org.jboss.netty.handler.codec.http.HttpHeaders;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.TimeUnit;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.Response;
/**
* Generate and grant access token to authorized users.
*/
@Path("/")
public class GrantAccessToken {
private static final Logger LOG = LoggerFactory.getLogger(GrantAccessToken.class);
private final TokenManager tokenManager;
private final Codec<AccessToken> tokenCodec;
private final CConfiguration cConf;
private final long tokenExpiration;
private final long extendedTokenExpiration;
/**
* Create a new GrantAccessToken object to generate tokens for authorized users.
*/
@Inject
public GrantAccessToken(TokenManager tokenManager,
Codec<AccessToken> tokenCodec,
CConfiguration cConfiguration) {
this.tokenManager = tokenManager;
this.tokenCodec = tokenCodec;
this.cConf = cConfiguration;
this.tokenExpiration = cConf.getLong(Constants.Security.TOKEN_EXPIRATION);
this.extendedTokenExpiration = cConf.getLong(Constants.Security.EXTENDED_TOKEN_EXPIRATION);
}
/**
* Initialize the TokenManager.
*/
public void init() {
tokenManager.start();
}
/**
* Stop the TokenManager.
*/
public void destroy() {
tokenManager.stop();
}
/**
* Paths to get Access Tokens.
*/
public static final class Paths {
public static final String GET_TOKEN = "token";
public static final String GET_EXTENDED_TOKEN = "extendedtoken";
}
/**
* Get an AccessToken.
*/
@Path(Paths.GET_TOKEN)
@GET
@Produces("application/json")
public Response token(@Context HttpServletRequest request, @Context HttpServletResponse response)
throws IOException, ServletException {
this.grantToken(request, response, tokenExpiration);
return Response.status(200).build();
}
/**
* Get a long lasting Access Token.
*/
@Path(Paths.GET_EXTENDED_TOKEN)
@GET
@Produces("application/json")
public Response extendedToken(@Context HttpServletRequest request, @Context HttpServletResponse response)
throws IOException, ServletException {
this.grantToken(request, response, extendedTokenExpiration);
return Response.status(200).build();
}
private void grantToken(HttpServletRequest request, HttpServletResponse response, long tokenValidity)
throws IOException, ServletException {
String username = request.getUserPrincipal().getName();
List<String> userGroups = Collections.emptyList();
long issueTime = System.currentTimeMillis();
long expireTime = issueTime + tokenValidity;
// Create and sign a new AccessTokenIdentifier to generate the AccessToken.
AccessTokenIdentifier tokenIdentifier = new AccessTokenIdentifier(username, userGroups, issueTime, expireTime);
AccessToken token = tokenManager.signIdentifier(tokenIdentifier);
LOG.debug("Issued token for user {}", username);
// Set response headers
response.setContentType("application/json;charset=UTF-8");
response.addHeader(HttpHeaders.Names.CACHE_CONTROL, "no-store");
response.addHeader(HttpHeaders.Names.PRAGMA, "no-cache");
// Set response body
JsonObject json = new JsonObject();
byte[] encodedIdentifier = Base64.encodeBase64(tokenCodec.encode(token));
json.addProperty(ExternalAuthenticationServer.ResponseFields.ACCESS_TOKEN,
new String(encodedIdentifier, Charsets.UTF_8));
json.addProperty(ExternalAuthenticationServer.ResponseFields.TOKEN_TYPE,
ExternalAuthenticationServer.ResponseFields.TOKEN_TYPE_BODY);
json.addProperty(ExternalAuthenticationServer.ResponseFields.EXPIRES_IN,
TimeUnit.SECONDS.convert(tokenValidity, TimeUnit.MILLISECONDS));
response.getOutputStream().print(json.toString());
response.setStatus(HttpServletResponse.SC_OK);
}
}