/*
* 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.service.resources.admin;
import com.codahale.metrics.annotation.Timed;
import com.codahale.metrics.annotation.ExceptionMetered;
import com.google.common.collect.ImmutableList;
import io.dropwizard.auth.AuthenticationException;
import io.dropwizard.auth.basic.BasicCredentials;
import io.dropwizard.java8.auth.Authenticator;
import java.net.URI;
import java.time.ZonedDateTime;
import java.util.Optional;
import javax.inject.Inject;
import javax.validation.Valid;
import javax.ws.rs.Consumes;
import javax.ws.rs.NotAuthorizedException;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.CacheControl;
import javax.ws.rs.core.NewCookie;
import javax.ws.rs.core.Response;
import keywhiz.api.LoginRequest;
import keywhiz.auth.User;
import keywhiz.auth.cookie.AuthenticatedEncryptedCookieFactory;
import keywhiz.auth.xsrf.XsrfProtection;
import keywhiz.service.config.Readonly;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import static javax.ws.rs.core.MediaType.APPLICATION_JSON;
/**
* @parentEndpointName login
*
* @resourceDescription Login to Keywhiz admin interface
*/
@Path("/admin/login")
public class SessionLoginResource {
private static final Logger logger = LoggerFactory.getLogger(SessionLoginResource.class);
private final Authenticator<BasicCredentials, User> userAuthenticator;
private final AuthenticatedEncryptedCookieFactory cookieFactory;
private final XsrfProtection xsrfProtection;
@Inject
public SessionLoginResource(@Readonly Authenticator<BasicCredentials, User> userAuthenticator,
AuthenticatedEncryptedCookieFactory cookieFactory, XsrfProtection xsrfProtection) {
this.userAuthenticator = userAuthenticator;
this.cookieFactory = cookieFactory;
this.xsrfProtection = xsrfProtection;
}
/**
* Login and set a session cookie
*
* @param request validated json request object
*
* @description Logs in using LDAP and sets session cookies to authorize further requests
* @responseMessage 200 Logged in successfully
* @responseMessage 401 Incorrect credentials or not authorized
*/
@Timed @ExceptionMetered
@POST
@Consumes(APPLICATION_JSON)
@Produces(APPLICATION_JSON)
public Response login(@Valid LoginRequest request) {
String username = request.username();
String password = String.copyValueOf(request.password());
Optional<User> optionalUser = Optional.empty();
try {
optionalUser = userAuthenticator.authenticate(new BasicCredentials(username, password));
} catch (AuthenticationException e) {
logger.warn("User authenticator threw something weird.", e);
}
if (!optionalUser.isPresent()) {
logger.info("User authentication failed at login for {}", username);
throw new NotAuthorizedException("");
}
logger.info("User logged in: {}", username);
Response.ResponseBuilder response = Response.ok();
cookiesForUser(optionalUser.get())
.forEach(response::cookie);
return response.build();
}
public ImmutableList<NewCookie> cookiesForUser(User user) {
ZonedDateTime expiration = ZonedDateTime.now().plusMinutes(15);
String session = cookieFactory.getSession(user, expiration);
NewCookie cookie = cookieFactory.cookieFor(session, expiration);
NewCookie xsrfCookie = xsrfProtection.generate(session);
return ImmutableList.of(cookie, xsrfCookie);
}
}