/**
* Copyright 2005-2014 Restlet
*
* The contents of this file are subject to the terms of one of the following
* open source licenses: Apache 2.0 or or EPL 1.0 (the "Licenses"). You can
* select the license that you prefer but you may not use this file except in
* compliance with one of these Licenses.
*
* You can obtain a copy of the Apache 2.0 license at
* http://www.opensource.org/licenses/apache-2.0
*
* You can obtain a copy of the EPL 1.0 license at
* http://www.opensource.org/licenses/eclipse-1.0
*
* See the Licenses for the specific language governing permissions and
* limitations under the Licenses.
*
* Alternatively, you can obtain a royalty free commercial license with less
* limitations, transferable or non-transferable, directly at
* http://restlet.com/products/restlet-framework
*
* Restlet is a registered trademark of Restlet S.A.S.
*/
package org.restlet.ext.oauth;
import java.io.IOException;
import org.json.JSONException;
import org.json.JSONObject;
import org.restlet.Response;
import org.restlet.data.ChallengeScheme;
import org.restlet.data.MediaType;
import org.restlet.data.Preference;
import org.restlet.data.Reference;
import org.restlet.data.Status;
import org.restlet.ext.json.JsonRepresentation;
import org.restlet.ext.oauth.internal.Scopes;
import org.restlet.ext.oauth.internal.Token;
import org.restlet.representation.Representation;
import org.restlet.resource.ClientResource;
/**
* Client resource used to acquire an OAuth token. Implements OAuth 2.0
* (RFC6749)
*
* @author Shotaro Uchida <fantom@xmaker.mx>
*/
public class AccessTokenClientResource extends ClientResource implements
OAuthResourceDefs {
private static class TokenResponse implements Token {
public static TokenResponse parseResponse(JSONObject result)
throws JSONException {
TokenResponse token = new TokenResponse();
token.accessToken = result.getString(ACCESS_TOKEN);
token.tokenType = result.getString(TOKEN_TYPE);
if (result.has(EXPIRES_IN)) {
token.expirePeriod = result.getInt(EXPIRES_IN);
}
if (result.has(REFRESH_TOKEN)) {
token.refreshToken = result.getString(REFRESH_TOKEN);
}
if (result.has(SCOPE)) {
token.scope = Scopes.parseScope(result.getString(SCOPE));
}
return token;
}
private String accessToken;
private Integer expirePeriod;
private String refreshToken;
private String[] scope;
private String tokenType;
public String getAccessToken() {
return accessToken;
}
public int getExpirePeriod() {
if (expirePeriod == null) {
throw new IllegalStateException("expires_in not included.");
}
return expirePeriod;
}
public String getRefreshToken() {
return refreshToken;
}
public String[] getScope() {
return scope;
}
public String getTokenType() {
return tokenType;
}
@SuppressWarnings("unused")
public boolean isExpirePeriodAvailable() {
return expirePeriod != null;
}
}
private ChallengeScheme authenticationScheme;
private String clientId;
private String clientSecret;
public AccessTokenClientResource(Reference tokenURI) {
super(tokenURI);
// set default scheme
authenticationScheme = ChallengeScheme.HTTP_BASIC;
}
@Override
public void doError(Status errorStatus) {
Representation representation = getResponse().getEntity();
if (representation.getMediaType().equals(MediaType.APPLICATION_JSON)) {
// Do not throw an exception here.
getLogger().fine("OAuth response is found.");
// XXX: after #doError, the representation will disposed in
// #handleInbound.
return;
}
// ResourceException will be thrown.
super.doError(errorStatus);
}
// We override to not dispose the OAuth error json body.
@Override
public Representation handleInbound(Response response) {
Representation result = null;
// Verify that the request was synchronous
if (response.getRequest().isSynchronous()) {
if (response.getStatus().isError()) {
doError(response.getStatus());
// DO NOT DISPOSE THE RESPONSE.
}/* else { */
result = (response == null) ? null : response.getEntity();
/* } */
}
return result;
}
public Token requestToken(OAuthParameters parameters)
throws OAuthException, IOException, JSONException {
if (authenticationScheme == null) {
// Use Body method
setupBodyClientCredentials(parameters);
} else {
setChallengeResponse(authenticationScheme, clientId, clientSecret);
}
Representation input = parameters.toRepresentation();
getClientInfo().getAcceptedMediaTypes().add(
new Preference<MediaType>(MediaType.APPLICATION_JSON));
JSONObject result = new JsonRepresentation(post(input)).getJsonObject();
if (result.has(ERROR)) {
throw OAuthException.toOAuthException(result);
}
TokenResponse token = TokenResponse.parseResponse(result);
if (token.scope == null) {
// Should be identical to the scope requested by the client.
token.scope = Scopes.parseScope(parameters.toForm().getFirstValue(
SCOPE));
}
return token;
}
public void setAuthenticationMethod(ChallengeScheme scheme) {
this.authenticationScheme = scheme;
}
public void setClientCredentials(String clientId, String clientSecret) {
this.clientId = clientId;
this.clientSecret = clientSecret;
}
protected void setupBodyClientCredentials(OAuthParameters parameters) {
parameters.add(CLIENT_ID, clientId);
if (clientSecret != null) {
parameters.add(CLIENT_SECRET, clientSecret);
}
}
}