Java tutorial
/* * Copyright (c) 2008-2017 Haulmont. * * 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 com.haulmont.restapi.auth; import com.google.common.base.Preconditions; import com.haulmont.cuba.core.global.ClientType; import com.haulmont.cuba.core.global.Configuration; import com.haulmont.cuba.core.global.GlobalConfig; import com.haulmont.cuba.core.sys.SecurityContext; import com.haulmont.cuba.security.auth.AuthenticationService; import com.haulmont.cuba.security.auth.TrustedClientCredentials; import com.haulmont.cuba.security.global.LoginException; import com.haulmont.cuba.security.global.RestApiAccessDeniedException; import com.haulmont.cuba.security.global.UserSession; import com.haulmont.restapi.config.RestApiConfig; import org.apache.commons.lang.StringUtils; import org.apache.http.HttpHeaders; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.security.authentication.BadCredentialsException; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.oauth2.common.OAuth2AccessToken; import org.springframework.security.oauth2.provider.*; import org.springframework.security.oauth2.provider.token.AbstractTokenGranter; import org.springframework.security.oauth2.provider.token.AuthorizationServerTokenServices; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; import javax.inject.Inject; import javax.servlet.http.HttpServletRequest; import java.util.*; import static com.haulmont.cuba.core.sys.AppContext.withSecurityContext; import static com.haulmont.restapi.auth.CubaTokenEnhancer.EXTENDED_DETAILS_ATTRIBUTE_PREFIX; import static com.haulmont.restapi.auth.CubaUserAuthenticationProvider.SESSION_ID_DETAILS_ATTRIBUTE; public class ExternalOAuthTokenGranter extends AbstractTokenGranter implements OAuthTokenIssuer { protected static final String GRANT_TYPE = "external"; private static final Logger log = LoggerFactory.getLogger(ExternalOAuthTokenGranter.class); protected ClientDetailsService clientDetailsService; protected OAuth2RequestFactory requestFactory; @Inject protected Configuration configuration; @Inject protected AuthenticationService authenticationService; protected ExternalOAuthTokenGranter(AuthorizationServerTokenServices tokenServices, ClientDetailsService clientDetailsService, OAuth2RequestFactory requestFactory) { super(tokenServices, clientDetailsService, requestFactory, GRANT_TYPE); this.clientDetailsService = clientDetailsService; this.requestFactory = requestFactory; } @Override public OAuth2AccessTokenResult issueToken(OAuth2AccessTokenRequest tokenRequest) { RestApiConfig config = configuration.getConfig(RestApiConfig.class); String login = tokenRequest.getLogin(); Locale locale = tokenRequest.getLocale(); Map<String, String> parameters = new HashMap<>(); parameters.put("username", login); parameters.put("client_id", config.getRestClientId()); parameters.put("scope", "rest-api"); parameters.put("grant", GRANT_TYPE); UserSession session; try { TrustedClientCredentials credentials = new TrustedClientCredentials(login, config.getTrustedClientPassword(), locale); credentials.setClientType(ClientType.REST_API); ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder .currentRequestAttributes(); if (attributes != null) { HttpServletRequest request = attributes.getRequest(); credentials.setIpAddress(request.getRemoteAddr()); credentials.setClientInfo(makeClientInfo(request.getHeader(HttpHeaders.USER_AGENT))); } else { credentials.setClientInfo(makeClientInfo("")); } credentials.setParams(tokenRequest.getLoginParams()); session = authenticationService.login(credentials).getSession(); } catch (RestApiAccessDeniedException ex) { log.info("User is not allowed to use the REST API {}", login); throw new BadCredentialsException("User is not allowed to use the REST API"); } catch (LoginException e) { log.info("Unable to issue token for REST API: {}", login); throw new BadCredentialsException("Bad credentials"); } parameters.put(SESSION_ID_DETAILS_ATTRIBUTE, session.getId().toString()); for (Map.Entry<String, String> tokenParam : tokenRequest.getTokenDetails().entrySet()) { parameters.put(EXTENDED_DETAILS_ATTRIBUTE_PREFIX + tokenParam.getKey(), tokenParam.getValue()); } // issue token using obtained Session, it is required for DB operations inside of persistent token store OAuth2AccessToken accessToken = withSecurityContext(new SecurityContext(session), () -> { ClientDetails authenticatedClient = clientDetailsService.loadClientByClientId(config.getRestClientId()); TokenRequest tr = getRequestFactory().createTokenRequest(parameters, authenticatedClient); return grant(GRANT_TYPE, tr); }); return new OAuth2AccessTokenResult(session, accessToken); } @Override public OAuth2AccessTokenResult issueToken(String login, Locale locale, Map<String, Object> loginParams) { OAuth2AccessTokenRequest tokenRequest = new OAuth2AccessTokenRequest(); tokenRequest.setLogin(login); tokenRequest.setLocale(locale); tokenRequest.setLoginParams(loginParams); return issueToken(tokenRequest); } @Override protected OAuth2Authentication getOAuth2Authentication(ClientDetails client, TokenRequest tokenRequest) { String externalPrincipal = tokenRequest.getRequestParameters().get("username"); String sessionId = tokenRequest.getRequestParameters().get(SESSION_ID_DETAILS_ATTRIBUTE); Preconditions.checkState(externalPrincipal != null); Preconditions.checkState(sessionId != null); OAuth2Request storedOAuth2Request = requestFactory.createOAuth2Request(client, tokenRequest); ExternalAuthenticationToken authentication = new ExternalAuthenticationToken(externalPrincipal, getRoleUserAuthorities(tokenRequest)); @SuppressWarnings("unchecked") Map<String, String> details = (Map<String, String>) authentication.getDetails(); if (details == null) { details = new HashMap<>(); } details.put(SESSION_ID_DETAILS_ATTRIBUTE, sessionId); authentication.setDetails(details); return new OAuth2Authentication(storedOAuth2Request, authentication); } protected List<GrantedAuthority> getRoleUserAuthorities(TokenRequest tokenRequest) { return new ArrayList<>(); } protected String makeClientInfo(String userAgent) { GlobalConfig globalConfig = configuration.getConfig(GlobalConfig.class); //noinspection UnnecessaryLocalVariable String serverInfo = String.format("REST API (%s:%s/%s) %s", globalConfig.getWebHostName(), globalConfig.getWebPort(), globalConfig.getWebContextName(), StringUtils.trimToEmpty(userAgent)); return serverInfo; } }