001/*
002 * (C) Copyright 2016 Nuxeo SA (http://nuxeo.com/) and others.
003 * 
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 * 
008 *     http://www.apache.org/licenses/LICENSE-2.0
009 * 
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 *  
016 * Contributors:
017 *     Kevin Leturc
018 */
019package org.nuxeo.ecm.liveconnect.onedrive.oauth;
020
021import java.io.IOException;
022import java.util.Objects;
023import java.util.Optional;
024
025import com.google.api.client.auth.oauth2.AuthorizationCodeFlow;
026import com.google.api.client.auth.oauth2.AuthorizationCodeTokenRequest;
027import com.google.api.client.auth.oauth2.Credential;
028import com.google.api.client.auth.oauth2.Credential.AccessMethod;
029import com.google.api.client.http.GenericUrl;
030import com.google.api.client.http.HttpExecuteInterceptor;
031import com.google.api.client.http.HttpTransport;
032import com.google.api.client.json.JsonFactory;
033
034/**
035 * We need to add some hook on {@link AuthorizationCodeFlow} as OneDrive for Business needs the resource parameter for
036 * token and refresh token requests. Furthermore their response don't follow OAuth standard for expires_in field. See
037 * https://github.com/google/google-oauth-java-client/issues/62
038 * 
039 * @since 8.2
040 */
041public class OneDriveAuthorizationCodeFlow extends AuthorizationCodeFlow {
042
043    private static final String RESOURCE_PARAMETER = "resource";
044
045    private final Optional<String> businessResource;
046
047    protected OneDriveAuthorizationCodeFlow(Builder builder) {
048        super(builder);
049        businessResource = Objects.requireNonNull(builder.businessResource);
050    }
051
052    @Override
053    public AuthorizationCodeTokenRequest newTokenRequest(String authorizationCode) {
054        OneDriveAuthorizationCodeTokenRequest tokenRequest = new OneDriveAuthorizationCodeTokenRequest(getTransport(),
055                getJsonFactory(), new GenericUrl(getTokenServerEncodedUrl()), authorizationCode);
056        businessResource.ifPresent(resourceURL -> tokenRequest.set(RESOURCE_PARAMETER, resourceURL));
057        return tokenRequest.setClientAuthentication(getClientAuthentication())
058                           .setRequestInitializer(getRequestInitializer())
059                           .setScopes(getScopes());
060    }
061
062    @Override
063    public Credential loadCredential(String userId) throws IOException {
064        return new OneDriveCredential(super.loadCredential(userId), businessResource);
065    }
066
067    public static class Builder extends AuthorizationCodeFlow.Builder {
068
069        Optional<String> businessResource = Optional.empty();
070
071        public Builder(AccessMethod method, HttpTransport transport, JsonFactory jsonFactory,
072                GenericUrl tokenServerUrl, HttpExecuteInterceptor clientAuthentication, String clientId,
073                String authorizationServerEncodedUrl) {
074            super(method, transport, jsonFactory, tokenServerUrl, clientAuthentication, clientId,
075                    authorizationServerEncodedUrl);
076        }
077
078        @Override
079        public OneDriveAuthorizationCodeFlow build() {
080            return new OneDriveAuthorizationCodeFlow(this);
081        }
082
083        public final Optional<String> getBusinessResource() {
084            return businessResource;
085        }
086
087        public Builder setBusinessResource(Optional<String> businessResource) {
088            this.businessResource = Objects.requireNonNull(businessResource);
089            return this;
090        }
091
092    }
093
094}