You are viewing a plain text version of this content. The canonical link for it is here.
Posted to issues@nifi.apache.org by "ASF GitHub Bot (JIRA)" <ji...@apache.org> on 2018/01/08 17:00:03 UTC

[jira] [Commented] (NIFI-4246) OAuth 2 Authorization support - Client Credentials Grant

    [ https://issues.apache.org/jira/browse/NIFI-4246?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=16316585#comment-16316585 ] 

ASF GitHub Bot commented on NIFI-4246:
--------------------------------------

Github user jdye64 commented on a diff in the pull request:

    https://github.com/apache/nifi/pull/2085#discussion_r160197726
  
    --- Diff: nifi-nar-bundles/nifi-oauth-bundle/nifi-oauth/src/main/java/org/apache/nifi/oauth/AbstractOAuthControllerService.java ---
    @@ -0,0 +1,172 @@
    +/*
    + * 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.nifi.oauth;
    +
    +import java.util.HashMap;
    +import java.util.Iterator;
    +import java.util.Map;
    +
    +import org.apache.nifi.components.PropertyDescriptor;
    +import org.apache.nifi.controller.AbstractControllerService;
    +import org.apache.nifi.controller.ConfigurationContext;
    +import org.apache.nifi.processor.util.StandardValidators;
    +import org.apache.nifi.reporting.InitializationException;
    +
    +
    +public abstract class AbstractOAuthControllerService
    +    extends AbstractControllerService implements OAuth2ClientService {
    +
    +    protected String accessToken = null;
    +    protected String refreshToken = null;
    +    protected String tokenType = null;
    +    protected long expiresIn = -1;
    +    protected long expiresTime = -1;
    +    protected long lastResponseTimestamp = -1;
    +    protected Map<String, String> extraHeaders = new HashMap<String, String>();
    +    protected String authUrl = null;
    +    protected long expireTimeSafetyNetSeconds = -1;
    +    protected String accessTokenRespName = null;
    +    protected String expireTimeRespName = null;
    +    protected String expireInRespName = null;
    +    protected String tokenTypeRespName = null;
    +    protected String scopeRespName = null;
    +
    +    public static final PropertyDescriptor AUTH_SERVER_URL = new PropertyDescriptor
    +            .Builder().name("OAuth2 Authorization Server URL")
    +            .displayName("OAuth2 Authorization Server")
    +            .description("OAuth2 Authorization Server that grants access to the protected resources on the behalf of the resource owner.")
    +            .required(true)
    +            .addValidator(StandardValidators.NON_EMPTY_VALIDATOR)
    +            .build();
    +
    +    public static final PropertyDescriptor RESPONSE_ACCESS_TOKEN_FIELD_NAME = new PropertyDescriptor
    +            .Builder().name("JSON response 'access_token' name")
    +            .displayName("JSON response 'access_token' name")
    +            .description("Name of the field in the JSON response that contains the access token. IETF OAuth2 spec default is 'access_token' if your API provider's" +
    +                    " response field is different this is where you can change that.")
    +            .defaultValue("access_token")
    +            .required(true)
    +            .addValidator(StandardValidators.NON_EMPTY_VALIDATOR)
    +            .build();
    +
    +    public static final PropertyDescriptor RESPONSE_EXPIRE_TIME_FIELD_NAME = new PropertyDescriptor
    +            .Builder().name("JSON response 'expire_time' name")
    +            .displayName("JSON response 'expire_time' name")
    +            .description("Name of the field in the JSON response that contains the expire time. IETF OAuth2 spec default is 'expire_time' if your API provider's" +
    +                    " response field is different this is where you can change that.")
    +            .defaultValue("expire_time")
    +            .required(true)
    +            .addValidator(StandardValidators.NON_EMPTY_VALIDATOR)
    +            .build();
    +
    +    public static final PropertyDescriptor RESPONSE_EXPIRE_IN_FIELD_NAME = new PropertyDescriptor
    +            .Builder().name("JSON response 'expire_in' name")
    +            .displayName("JSON response 'expire_in' name")
    +            .description("Name of the field in the JSON response that contains the expire in. IETF OAuth2 spec default is 'expire_in' if your API provider's" +
    +                    " response field is different this is where you can change that.")
    +            .defaultValue("expire_in")
    +            .required(true)
    +            .addValidator(StandardValidators.NON_EMPTY_VALIDATOR)
    +            .build();
    +
    +    public static final PropertyDescriptor RESPONSE_TOKEN_TYPE_FIELD_NAME = new PropertyDescriptor
    +            .Builder().name("JSON response 'token_type' name")
    +            .displayName("JSON response 'token_type' name")
    +            .description("Name of the field in the JSON response that contains the token type. IETF OAuth2 spec default is 'token_type' if your API provider's" +
    +                    " response field is different this is where you can change that.")
    +            .defaultValue("token_type")
    +            .required(true)
    +            .addValidator(StandardValidators.NON_EMPTY_VALIDATOR)
    +            .build();
    +
    +    public static final PropertyDescriptor RESPONSE_SCOPE_FIELD_NAME = new PropertyDescriptor
    +            .Builder().name("JSON response 'scope' name")
    +            .displayName("JSON response 'scope' name")
    +            .description("Name of the field in the JSON response that contains the scope. IETF OAuth2 spec default is 'scope' if your API provider's" +
    +                    " response field is different this is where you can change that.")
    +            .defaultValue("scope")
    +            .required(true)
    +            .addValidator(StandardValidators.NON_EMPTY_VALIDATOR)
    +            .build();
    +
    +    public static final PropertyDescriptor EXPIRE_TIME_SAFETY_NET = new PropertyDescriptor
    +            .Builder().name("Expire time safety net in seconds")
    +            .displayName("Expire time safety net in seconds")
    +            .description("There can be a chance that the authentication server and the NiFi agent clocks could be out of sync. Expires In is an OAuth standard " +
    +                    "that tells when the access token received will be invalidated. Comparing the current system clock to that value and understanding if the " +
    +                    "access token is still valid can be achieved this way. However since the clocks can be out of sync with the authentication server " +
    +                    "this property ensures that the access token can be refreshed at a configurable interval before it actual expires to ensure no downtime " +
    +                    "waiting on new tokens from the authentication server.")
    +            .defaultValue("10")
    +            .required(true)
    +            .addValidator(StandardValidators.NON_EMPTY_VALIDATOR)
    +            .build();
    +
    +    protected void onEnabled(final ConfigurationContext context)
    +            throws InitializationException {
    +        Map<PropertyDescriptor, String> allProperties = context.getProperties();
    +        Iterator<PropertyDescriptor> itr = allProperties.keySet().iterator();
    +        while (itr.hasNext()) {
    +            PropertyDescriptor pd = itr.next();
    +            if (pd.isDynamic()) {
    +                extraHeaders.put(pd.getName(), allProperties.get(pd));
    +            }
    +        }
    +
    +        this.authUrl = context.getProperty(AUTH_SERVER_URL).getValue();
    +        this.expireTimeSafetyNetSeconds = new Long(context.getProperty(EXPIRE_TIME_SAFETY_NET).getValue());
    +
    +        // Name of the OAuth2 spec fields that should be extracted from the JSON authentication response. While in theory every provider should be
    +        // using the same names in the response JSON that rarely happens. These values are used to ensure that if the provider does NOT follow the
    +        // spec the user can still use this integration approach instead of having to write something custom.
    +        this.accessTokenRespName = context.getProperty(RESPONSE_ACCESS_TOKEN_FIELD_NAME).getValue();
    +        this.expireTimeRespName = context.getProperty(RESPONSE_EXPIRE_TIME_FIELD_NAME).getValue();
    +        this.expireInRespName = context.getProperty(RESPONSE_EXPIRE_IN_FIELD_NAME).getValue();
    +        this.tokenTypeRespName = context.getProperty(RESPONSE_TOKEN_TYPE_FIELD_NAME).getValue();
    +        this.scopeRespName = context.getProperty(RESPONSE_SCOPE_FIELD_NAME).getValue();
    +    }
    +
    +    public boolean isOAuthTokenExpired() {
    +        if (expiresTime == -1 && expiresIn == -1)
    +            return true;
    +
    +        if (expiresTime > 0) {
    +            // Use the actual time that the token will authenticate
    +            if ((expiresTime - (expireTimeSafetyNetSeconds * 1000)) <= System.currentTimeMillis()) {
    --- End diff --
    
    Andy. I think I could have chosen a better name for the "expireTimeSafetyNetSeconds" variable. My intended behavior was for that variable to be more of a method for causing the auth token to be refresh before the token was actually expired. My thought process around this was if users could control having their token refreshed before they were actually invalid it would allow them a rough way to help prevent bottlenecking of processing when the token was invalid and the processors using the controller service were having to wait on the token to be refreshed. Does that make sense?


> OAuth 2 Authorization support - Client Credentials Grant
> --------------------------------------------------------
>
>                 Key: NIFI-4246
>                 URL: https://issues.apache.org/jira/browse/NIFI-4246
>             Project: Apache NiFi
>          Issue Type: Improvement
>            Reporter: Jeremy Dyer
>            Assignee: Jeremy Dyer
>
> If your interacting with REST endpoints on the web chances are you are going to run into an OAuth2 secured webservice. The IETF (Internet Engineering Task Force) defines 4 methods in which OAuth2 authorization can occur. This JIRA is focused solely on the Client Credentials Grant method defined at https://tools.ietf.org/html/rfc6749#section-4.4
> This implementation should provide a ControllerService in which the enduser can configure the credentials for obtaining the authorization grant (access token) from the resource owner. In turn a new property will be added to the InvokeHTTP processor (if it doesn't already exist from one of the other JIRA efforts similar to this one) where the processor can reference this controller service to obtain the access token and insert the appropriate HTTP header (Authorization: Bearer{access_token}) so that the InvokeHTTP processor can interact with the OAuth protected resources without having to worry about setting up the credentials for each InvokeHTTP processor saving time and complexity.



--
This message was sent by Atlassian JIRA
(v6.4.14#64029)