Skip to content

Commit

Permalink
Integrated the global settings for oauth apps issues syndesisio#424 and
Browse files Browse the repository at this point in the history
syndesisio/syndesis-ui#556.

When a user updates the oauth id/secret for a connection in the settings page, the oauth credentials registry now gets updated.
  • Loading branch information
chirino committed Jul 20, 2017
1 parent 04b9642 commit cf63070
Show file tree
Hide file tree
Showing 9 changed files with 315 additions and 45 deletions.
2 changes: 0 additions & 2 deletions credential/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -126,13 +126,11 @@
<dependency>
<groupId>com.github.mikegirard</groupId>
<artifactId>spring-social-salesforce</artifactId>
<optional>true</optional>
</dependency>

<dependency>
<groupId>org.springframework.social</groupId>
<artifactId>spring-social-twitter</artifactId>
<optional>true</optional>
</dependency>

<!-- === Test ============================================================================ -->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,6 @@ public interface CredentialProviderLocator {
*
* @param credentialProvider the provider to add
*/
public <A, T> void addCredentialProvider(final CredentialProvider<A, T> credentialProvider);
<A, T> void addCredentialProvider(final CredentialProvider<A, T> credentialProvider);

}
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,13 @@ public class SalesforceConfiguration {

protected final SalesforceConnectionFactory salesforce;

protected final class SalesforceApplicator extends OAuth2Applicator {
protected static final class SalesforceApplicator extends OAuth2Applicator {

public SalesforceApplicator(final SocialProperties socialProperties) {
private final SalesforceConnectionFactory salesforce;

public SalesforceApplicator(SalesforceConnectionFactory salesforce, final SocialProperties socialProperties) {
super(socialProperties);
this.salesforce = salesforce;

setClientIdProperty("clientId");
setClientSecretProperty("clientSecret");
Expand Down Expand Up @@ -74,13 +77,7 @@ public SalesforceConfiguration(final SalesforceProperties salesforceProperties)
protected SalesforceConfiguration(final SalesforceConnectionFactory salesforce,
final SocialProperties salesforceProperties) {
this.salesforce = salesforce;
applicator = new SalesforceApplicator(salesforceProperties);
}

@Bean
public CredentialProvider<Salesforce, AccessGrant> create() {
return new DefaultCredentialProvider<>(
"salesforce", salesforce, applicator);
applicator = new SalesforceApplicator(this.salesforce, salesforceProperties);
}

protected static SalesforceConnectionFactory
Expand All @@ -96,4 +93,16 @@ public CredentialProvider<Salesforce, AccessGrant> create() {
return salesforce;
}

@Bean
public CredentialProvider<Salesforce, AccessGrant> create() {
return new DefaultCredentialProvider<>(
"salesforce", salesforce, applicator);
}

public static CredentialProvider<Salesforce, AccessGrant> create(final SalesforceProperties salesforceProperties) {
SalesforceConnectionFactory connectionFactory = createConnectionFactory(salesforceProperties);
return new DefaultCredentialProvider<>(
"salesforce", connectionFactory, new SalesforceApplicator(connectionFactory, salesforceProperties));
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -36,22 +36,25 @@
@EnableConfigurationProperties(TwitterProperties.class)
public class TwitterConfiguration {


private final OAuth1Applicator applicator;
private final TwitterConnectionFactory twitter;
private final TwitterProperties properties;

@Autowired
protected TwitterConfiguration(final TwitterProperties properties) {
twitter = new TwitterConnectionFactory(properties.getAppId(), properties.getAppSecret());
applicator = new OAuth1Applicator(properties);
applicator.setConsumerKeyProperty("consumerKey");
applicator.setConsumerSecretProperty("consumerSecret");
applicator.setAccessTokenSecretProperty("accessTokenSecret");
applicator.setAccessTokenValueProperty("accessToken");
this.properties = properties;
}

@Bean
public CredentialProvider<Twitter, OAuthToken> create() {
return create(properties);
}

public static CredentialProvider<Twitter, OAuthToken> create(TwitterProperties properties) {
TwitterConnectionFactory twitter = new TwitterConnectionFactory(properties.getAppId(), properties.getAppSecret());
OAuth1Applicator applicator = new OAuth1Applicator(properties);
applicator.setConsumerKeyProperty("consumerKey");
applicator.setConsumerSecretProperty("consumerSecret");
applicator.setAccessTokenSecretProperty("accessTokenSecret");
applicator.setAccessTokenValueProperty("accessToken");
return new DefaultCredentialProvider<>(
"twitter", twitter, applicator);
}
Expand Down
5 changes: 5 additions & 0 deletions rest/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,11 @@
<artifactId>hibernate-jpa-2.1-api</artifactId>
</dependency>

<dependency>
<groupId>org.jboss.spec.javax.annotation</groupId>
<artifactId>jboss-annotations-api_1.2_spec</artifactId>
</dependency>

<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,15 @@
*/
package io.syndesis.rest.v1.handler.setup;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.TreeSet;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiParam;
import io.syndesis.core.SuppressFBWarnings;
import io.syndesis.dao.manager.DataManager;
import io.syndesis.model.connection.ConfigurationProperty;
import io.syndesis.model.connection.Connector;
import org.springframework.stereotype.Component;

import javax.persistence.EntityNotFoundException;
import javax.validation.Valid;
import javax.validation.constraints.NotNull;
import javax.ws.rs.Consumes;
Expand All @@ -32,14 +35,11 @@
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;

import io.swagger.annotations.Api;
import io.syndesis.core.SuppressFBWarnings;
import io.syndesis.dao.manager.DataManager;
import io.syndesis.model.connection.ConfigurationProperty;
import io.syndesis.model.connection.Connector;

import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.TreeSet;

/**
* This rest endpoint handles working with global oauth settings.
Expand Down Expand Up @@ -77,19 +77,39 @@ public List<OAuthApp> get() {
List<Connector> items = dataMgr.fetchAll(Connector.class).getItems();
items.forEach(connector -> {
if (isOauthConnector(connector)) {
OAuthApp app = new OAuthApp();
app.id = connector.getId().get();
app.name = connector.getName();
app.icon = connector.getIcon();
app.clientId = getPropertyTaggedAs(connector, "oauth-client-id");
app.clientSecret = getPropertyTaggedAs(connector, "oauth-client-secret");
apps.add(app);
apps.add(createOAuthApp(connector));
}
});

return apps;
}

@GET
@Produces(MediaType.APPLICATION_JSON)
@Path(value = "/{id}")
public OAuthApp get(@PathParam("id") @ApiParam(required = true) String id) {

Connector connector = dataMgr.fetch(Connector.class, id);
if( connector == null ) {
throw new EntityNotFoundException();
}
if (isOauthConnector(connector)) {
return createOAuthApp(connector);
} else {
throw new EntityNotFoundException();
}
}

private static OAuthApp createOAuthApp(Connector connector) {
OAuthApp app = new OAuthApp();
app.id = connector.getId().get();
app.name = connector.getName();
app.icon = connector.getIcon();
app.clientId = getPropertyTaggedAs(connector, "oauth-client-id");
app.clientSecret = getPropertyTaggedAs(connector, "oauth-client-secret");
return app;
}

@PUT
@Path(value = "/{id}")
@Consumes("application/json")
Expand All @@ -111,15 +131,15 @@ public void update(@NotNull @PathParam("id") String id, @NotNull @Valid OAuthApp
dataMgr.update(connector);
}

private boolean isOauthConnector(Connector connector) {
private static boolean isOauthConnector(Connector connector) {
TreeSet EMPTY = new TreeSet();
return connector.getProperties().values().stream().anyMatch(x -> {
return x.getTags().orElse(EMPTY).contains("oauth-client-id");
}
);
}

private String getPropertyTaggedAs(Connector connector, String name) {
private static String getPropertyTaggedAs(Connector connector, String name) {
if( connector.getProperties() == null ) {
return null;
}
Expand All @@ -132,7 +152,7 @@ private String getPropertyTaggedAs(Connector connector, String name) {
return null;
}

private void setPropertyTaggedAs(Connector connector, Map<String, String> configuredProperties, String name, String value) {
private static void setPropertyTaggedAs(Connector connector, Map<String, String> configuredProperties, String name, String value) {
TreeSet EMPTY = new TreeSet();
for (Map.Entry<String,ConfigurationProperty> entry : connector.getProperties().entrySet()) {
if( entry.getValue().getTags().orElse(EMPTY).contains(name) ) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
/**
* Copyright (C) 2016 Red Hat, Inc.
*
* 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 io.syndesis.rest.v1.handler.setup;

import io.syndesis.core.EventBus;
import io.syndesis.core.Json;
import io.syndesis.credential.CredentialProviderLocator;
import io.syndesis.credential.salesforce.SalesforceConfiguration;
import io.syndesis.credential.salesforce.SalesforceProperties;
import io.syndesis.credential.twitter.TwitterConfiguration;
import io.syndesis.model.ChangeEvent;
import io.syndesis.model.Kind;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.autoconfigure.social.TwitterProperties;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.persistence.EntityNotFoundException;
import java.io.IOException;
import java.util.Optional;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
* This component handles initializing and updating the CredentialProviderLocator
* from the DB state.
*/
@Component
public class OAuthAppToCredentialsBridge {

private static final Logger LOG = LoggerFactory.getLogger(OAuthAppToCredentialsBridge.class);

private final OAuthAppHandler oAuthAppHandler;
private final CredentialProviderLocator locator;
private final Optional<EventBus> bus;
private ExecutorService executor;

public OAuthAppToCredentialsBridge(OAuthAppHandler oAuthAppHandler, CredentialProviderLocator locator, Optional<EventBus> bus) {
this.oAuthAppHandler = oAuthAppHandler;
this.locator = locator;
this.bus = bus;
}

@PostConstruct
public void init() {

if( bus.isPresent() ) {
executor = Executors.newSingleThreadExecutor();
bus.get().subscribe(getClass().getName(), getChangeEventSubscription());
}

// lets look at the app configs stored in the DB...
for (OAuthAppHandler.OAuthApp app : oAuthAppHandler.get()) {
registerCredentialProvider(app);
}
}

@PreDestroy
public void shutdown() {
if( bus.isPresent() ) {
bus.get().unsubscribe(getClass().getName());
executor.shutdown();
}
}

private EventBus.Subscription getChangeEventSubscription() {
return (event, data) -> {
// Never do anything that could block in this callback!
if (event!=null && "change-event".equals(event)) {
try {
ChangeEvent changeEvent = Json.mapper().readValue(data, ChangeEvent.class);
if (changeEvent != null) {
changeEvent.getId().ifPresent(id -> {
changeEvent.getKind()
.map(Kind::from)
.filter(k -> k == Kind.Connector)
.ifPresent(k -> {
executor.execute(() -> onConnectorUpdated(id));
});
});
}
} catch (IOException e) {
LOG.error("Error while processing change-event " + data, e);
}
}
};
}

private void onConnectorUpdated(String connectorId) {
OAuthAppHandler.OAuthApp oAuthApp = null;
try {
oAuthApp = oAuthAppHandler.get(connectorId);
} catch (EntityNotFoundException e) {
// Not all connectors will be oauth apps..
return;
}
registerCredentialProvider(oAuthApp);
}

public void registerCredentialProvider(OAuthAppHandler.OAuthApp app) {
// is the app configured?
if( isSet(app.clientId) && isSet(app.clientSecret) ) {
if( "twitter".equals(app.id) ) {
TwitterProperties props = new TwitterProperties();
props.setAppId(app.clientId);
props.setAppSecret(app.clientSecret);
locator.addCredentialProvider(TwitterConfiguration.create(props));
}
if( "twitter".equals(app.id) ) {
SalesforceProperties props = new SalesforceProperties();
props.setAppId(app.clientId);
props.setAppSecret(app.clientSecret);
locator.addCredentialProvider(SalesforceConfiguration.create(props));
}
}
}

private static boolean isSet(String value) {
return value!=null && !value.isEmpty();
}
}
Loading

0 comments on commit cf63070

Please sign in to comment.