org.midonet.api.auth.keystone.v2_0.KeystoneService.java Source code

Java tutorial

Introduction

Here is the source code for org.midonet.api.auth.keystone.v2_0.KeystoneService.java

Source

/*
 * Copyright 2014 Midokura SARL
 *
 * 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 org.midonet.api.auth.keystone.v2_0;

import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.List;
import java.util.TimeZone;
import javax.servlet.http.HttpServletRequest;

import com.google.inject.Inject;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import org.midonet.api.auth.*;
import org.midonet.api.auth.keystone.KeystoneConfig;
import org.midonet.api.auth.keystone.KeystoneInvalidFormatException;

/**
 * Keystone Service.
 */
public class KeystoneService implements AuthService {

    private final static Logger log = LoggerFactory.getLogger(KeystoneService.class);

    public final static String HEADER_X_AUTH_PROJECT = "X-Auth-Project";
    public final static String KEYSTONE_TOKEN_EXPIRED_FORMAT = "yyyy-MM-dd'T'HH:mm:ss'Z'";

    private final KeystoneClient client;
    private final KeystoneConfig config;

    /**
     * Create a KeystoneService object from a KeystoneConfig object.
     *
     * @param client
     *            KeystoneClient object
     * @param config
     *            KeystoneConfig object.
     */
    @Inject
    public KeystoneService(KeystoneClient client, KeystoneConfig config) {
        this.client = client;
        this.config = config;
    }

    private String convertToAuthRole(String role) {
        String roleLowerCase = role.toLowerCase();
        if (roleLowerCase.equals(config.getAdminRole())) {
            return AuthRole.ADMIN;
        } else if (roleLowerCase.equals(config.getTenantAdminRole())) {
            return AuthRole.TENANT_ADMIN;
        } else if (roleLowerCase.equals(config.getTenantUserRole())) {
            return AuthRole.TENANT_USER;
        } else {
            // Unknown roles are ignored.
            return null;
        }
    }

    private UserIdentity getUserIdentity(KeystoneAccess authAccess) {
        log.debug("KeystoneService.getUserIdentity entered.");

        KeystoneAccess.Access access = authAccess.getAccess();
        if (access.getUser() == null || access.getUser().getRoles() == null) {
            throw new IllegalArgumentException("User information is missing from this access object.");
        }

        if (access.getToken() == null || access.getToken().getTenant() == null) {
            throw new IllegalArgumentException("Tenant information is missing from this access object.");
        }

        UserIdentity userIdentity = new UserIdentity();
        userIdentity.setTenantId(access.getToken().getTenant().getId());
        userIdentity.setTenantName(access.getToken().getTenant().getName());
        userIdentity.setToken(access.getToken().getId());
        userIdentity.setUserId(access.getUser().getId());

        String r;
        for (KeystoneAccess.Access.User.Role role : access.getUser().getRoles()) {
            r = convertToAuthRole(role.getName());
            if (r != null) {
                userIdentity.addRole(r);
            }
        }

        log.debug("KeystoneService.getUserIdentity exiting: {}", userIdentity);
        return userIdentity;
    }

    private Token getToken(KeystoneAccess access) throws KeystoneInvalidFormatException {

        Token token = new Token();
        token.setKey(access.getAccess().getToken().getId());

        // Make sure the expired is converted to Date
        String expiredSrc = access.getAccess().getToken().getExpires();
        if (expiredSrc != null) {
            DateFormat df = new SimpleDateFormat(KEYSTONE_TOKEN_EXPIRED_FORMAT);
            df.setTimeZone(TimeZone.getTimeZone("GMT"));
            try {
                token.setExpires(df.parse(expiredSrc));
            } catch (ParseException e) {
                throw new KeystoneInvalidFormatException("Unrecognizable keystone expired date format.", e);
            }
        }

        return token;
    }

    private int parseLimit(HttpServletRequest request) {
        String limit = request.getParameter(KeystoneClient.LIMIT_QUERY);
        if (StringUtils.isEmpty(limit)) {
            return 0;
        }

        try {
            return Integer.parseInt(limit);
        } catch (RuntimeException ex) {
            log.warn("Invalid limit value passed in: " + limit);
            return 0;
        }
    }

    @Override
    public UserIdentity getUserIdentityByToken(String token) throws AuthException {
        log.debug("KeystoneService: entered getUserIdentityByToken. Token={}", token);

        if (StringUtils.isEmpty(token)) {
            // Don't allow empty token
            throw new InvalidCredentialsException("No token was passed in.");
        }

        KeystoneAccess access = client.getToken(token);

        // Parse the JSON response
        return (access == null) ? null : getUserIdentity(access);
    }

    @Override
    public Token login(String username, String password, HttpServletRequest request) throws AuthException {

        // For Keystone, since we need a scoped token, project is required.
        String project = request.getHeader(HEADER_X_AUTH_PROJECT);

        if (StringUtils.isEmpty(project)) {
            // the project was not specified in the request, so we need
            // to try and obtain it from the config.
            project = this.config.getAdminName();
            if (StringUtils.isEmpty(project)) {
                throw new InvalidCredentialsException("Project missing");
            }
        }

        // Construct the credentials
        KeystoneAuthCredentials credentials = new KeystoneAuthCredentials(username, password, project);

        // POST to get the token
        KeystoneAccess access = client.createToken(credentials);

        // Return the token
        return getToken(access);
    }

    /**
     * Gets a {@link Tenant} object from Keystone server.
     *
     * @param id Tenant ID
     * @return {@link Tenant} object
     * @throws AuthException
     */
    @Override
    public Tenant getTenant(String id) throws AuthException {
        log.debug("KeystoneService.getTenant entered.  id: " + id);

        KeystoneTenant tenant = client.getTenant(id);
        return (tenant == null) ? null : tenant.getTenant();
    }

    /**
     * Gets a list of tenants from the Keystone identity service, and returns
     * the result in a list of {@link Tenant} objects.
     *
     * @param request Keystone API v2.0 accepts the following query string
     *                parameters:
     *                <ul>
     *                <li>marker: ID of the last tenant in the previous request.
     *                The result set from this request starts from the tenant
     *                whose ID is after this one.</li>
     *                <li>limit: Number of tenants to fetch.</li>
     *                </ul>
     *                All other request fields are ignored.
     * @return  A list of {@link Tenant} objects representing the tenants in
     *          Keystone.
     * @throws AuthException
     */
    @Override
    public List<Tenant> getTenants(HttpServletRequest request) throws AuthException {
        log.debug("KeystoneService.getTenants entered.  Request: " + request);

        // Parse out marker and limit
        String marker = request.getParameter(KeystoneClient.MARKER_QUERY);
        int limit = parseLimit(request);

        KeystoneTenantList tenantList = client.getTenants(marker, limit);

        log.debug("KeystoneService.getTenants exiting.  " + tenantList.getTenants().size()
                + " tenants found with marker = " + marker + ", limit = ", +limit);
        return (List<Tenant>) tenantList.get();
    }
}