/** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you 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.apache.cxf.rs.security.oauth2.client; import java.net.URI; import java.util.Collections; import org.apache.cxf.configuration.security.AuthorizationPolicy; import org.apache.cxf.jaxrs.client.WebClient; import org.apache.cxf.message.Message; import org.apache.cxf.rs.security.oauth2.common.ClientAccessToken; import org.apache.cxf.rs.security.oauth2.provider.OAuthJSONProvider; import org.apache.cxf.rs.security.oauth2.utils.OAuthConstants; import org.apache.cxf.rs.security.oauth2.utils.OAuthUtils; import org.apache.cxf.transport.http.auth.HttpAuthSupplier; public class BearerAuthSupplier extends AbstractAuthSupplier implements HttpAuthSupplier { private Consumer consumer; private String accessTokenServiceUri; private boolean refreshEarly; public BearerAuthSupplier() { super(OAuthConstants.BEARER_AUTHORIZATION_SCHEME); } public boolean requiresRequestCaching() { return true; } public String getAuthorization(AuthorizationPolicy authPolicy, URI currentURI, Message message, String fullHeader) { if (getClientAccessToken().getTokenKey() == null) { return null; } if (fullHeader == null) { // regular authorization if (refreshEarly) { refreshAccessTokenIfExpired(authPolicy); } return createAuthorizationHeader(); } // the last call resulted in 401, trying to refresh the token(s) if (refreshAccessToken(authPolicy)) { return createAuthorizationHeader(); } else { return null; } } private void refreshAccessTokenIfExpired(AuthorizationPolicy authPolicy) { ClientAccessToken at = getClientAccessToken(); if (OAuthUtils.isExpired(at.getIssuedAt(), at.getExpiresIn())) { refreshAccessToken(authPolicy); } } private boolean refreshAccessToken(AuthorizationPolicy authPolicy) { ClientAccessToken at = getClientAccessToken(); if (at.getRefreshToken() == null) { return false; } // Client id and secret are needed to refresh the tokens // AuthorizationPolicy can hold them by default, Consumer can also be injected into this supplier // and checked if the policy is null. // Client TLS authentication is also fine as an alternative authentication mechanism, // how can we check here that a 2-way TLS has been set up ? Consumer theConsumer = consumer; if (theConsumer == null && authPolicy != null && authPolicy.getUserName() != null && authPolicy.getPassword() != null) { theConsumer = new Consumer(authPolicy.getUserName(), authPolicy.getPassword()); return false; } if (theConsumer == null) { return false; } // Can WebCient be safely constructed at HttpConduit initialization time ? // If yes then createAccessTokenServiceClient() can be called inside // setAccessTokenServiceUri, though given that the token refreshment would // not be done on every request the current approach is quite reasonable WebClient accessTokenService = createAccessTokenServiceClient(); setClientAccessToken(OAuthClientUtils.refreshAccessToken(accessTokenService, theConsumer, at)); return true; } WebClient createAccessTokenServiceClient() { return WebClient.create(accessTokenServiceUri, Collections.singletonList(new OAuthJSONProvider())); } public void setRefreshToken(String refreshToken) { getClientAccessToken().setRefreshToken(refreshToken); } public void setAccessTokenServiceUri(String uri) { this.accessTokenServiceUri = uri; } public Consumer getConsumer() { return consumer; } public void setConsumer(Consumer consumer) { this.consumer = consumer; } public void setRefreshEarly(boolean refreshEarly) { this.refreshEarly = refreshEarly; } }