including keyclocak group IDs in token - token

I am new to keyclocak. I have group assignments for users, and I was able to enable a group mapper, which puts groups (names only) in the token returned to a client. In my app, I need to associate data with groups, so I'd like for a way to add group IDs to the token.
Is there a way I can add the group ID to the token? Or, can my app query for group ids/names without having to have admin credentials on keycloak?

You can use a custom protocol mapper:
package org.sample;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import org.keycloak.models.ClientSessionContext;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.ProtocolMapperModel;
import org.keycloak.models.UserSessionModel;
import org.keycloak.protocol.oidc.mappers.AbstractOIDCProtocolMapper;
import org.keycloak.protocol.oidc.mappers.OIDCAccessTokenMapper;
import org.keycloak.protocol.oidc.mappers.OIDCAttributeMapperHelper;
import org.keycloak.protocol.oidc.mappers.OIDCIDTokenMapper;
import org.keycloak.protocol.oidc.mappers.UserInfoTokenMapper;
import org.keycloak.provider.ProviderConfigProperty;
import org.keycloak.representations.IDToken;
public class GroupIdProtocolMapper extends AbstractOIDCProtocolMapper implements OIDCAccessTokenMapper, OIDCIDTokenMapper, UserInfoTokenMapper {
public static final String PROVIDER_ID = "group-id-protocol-mapper";
private static final List<ProviderConfigProperty> configProperties = new ArrayList<>();
static {
OIDCAttributeMapperHelper.addTokenClaimNameConfig(configProperties);
OIDCAttributeMapperHelper.addIncludeInTokensConfig(configProperties, GroupIdProtocolMapper.class);
}
#Override
public String getId() {
return PROVIDER_ID;
}
#Override
public String getDisplayCategory() {
return TOKEN_MAPPER_CATEGORY;
}
#Override
public String getDisplayType() {
return "Group Id";
}
#Override
public String getHelpText() {
return "Map user group id to a token claim.";
}
#Override
public List<ProviderConfigProperty> getConfigProperties() {
return configProperties;
}
#Override
protected void setClaim(IDToken token, ProtocolMapperModel mappingModel, UserSessionModel userSession, KeycloakSession keycloakSession,
ClientSessionContext clientSessionCtx) {
List<String> groups = (List)userSession.getUser().getGroupsStream().map((g) -> {
return g.getId();
}).collect(Collectors.toList());
String protocolClaim = (String)mappingModel.getConfig().get("claim.name");
OIDCAttributeMapperHelper.mapClaim(token, mappingModel, groups);
}
}

Related

Whitelisting application properties in Spring Cloud Data Flow

When I create a custom app for SCDF I can, according to the reference define relevant properties that are visible through the dashboard when creating a new stream/task. I created a spring-configuration-metadata-whitelist.properties file like this:
configuration-properties.classes=com.example.MySourceProperties
configuration-properties.names=my.prop1,my.prop2
When I create a new stream definition through the dashboard all properties defined in com.example.MySourceProperties are displayed in the properties dialog, but my.prop1 and my.prop2 are not. Both properties aren't optional and must always be set by the user. How can I include them in the properties dialog?
This tells it which class to pull these properties from Task1 properties class
That we can use with "#EnableConfigurationProperties(Task1Properties.class) declaration
configuration-properties.classes=com.shifthunter.tasks.Task1Properties
Task1Properties.java
package com.shifthunter.tasks;
import org.springframework.boot.context.properties.ConfigurationProperties;
#ConfigurationProperties("pulldata-task")
public class Task1Properties {
/**
* The path to get the source doc from
*/
private String sourceFilePath;
/**
* The path to put the destination doc
*/
private String destinationFilePath;
/**
* Property to drive the exit code
*/
private String controlMessage;
public String getSourceFilePath() {
return sourceFilePath;
}
public void setSourceFilePath(String sourceFilePath) {
this.sourceFilePath = sourceFilePath;
}
public String getDestinationFilePath() {
return destinationFilePath;
}
public void setDestinationFilePath(String destinationFilePath) {
this.destinationFilePath = destinationFilePath;
}
public String getControlMessage() {
return controlMessage;
}
public void setControlMessage(String controlMessage) {
this.controlMessage = controlMessage;
}
}
ShiftHunterTaskPullDataApp.java
package com.shifthunter.tasks;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cloud.task.configuration.EnableTask;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
#EnableTask
#EnableConfigurationProperties(Task1Properties.class)
#SpringBootApplication
public class ShiftHunterTaskPullDataApp {
public static void main(String[] args) {
SpringApplication.run(ShiftHunterTaskPullDataApp.class, args);
}
#Bean
public Task1 task1() {
return new Task1();
}
public class Task1 implements CommandLineRunner {
#Autowired
private Task1Properties config;
#Override
public void run(String... strings) throws Exception {
System.out.println("source: " + config.getSourceFilePath());
System.out.println("destination: " + config.getDestinationFilePath());
System.out.println("control message: " + config.getControlMessage());
if(config.getControlMessage().equals("fail")) {
System.out.println("throwing an exception ...");
throw new Exception("I'm ANGRY");
}
System.out.println("pulldata-task complete!");
}
}
}
Sream Dataflow task-pull-data
app register --name task-pull-data --type task --uri maven://com.shifthunter.tasks:shifthunter-task-pulldata:jar:0.0.1-SNAPSHOT
task-pull-data - Details

Adding Swagger to Dropwizard application, need to provide instance of SwaggerBundleConfiguration?

I'm super new to all of these frameworks so please try and bear with me here with what feels like should be a super simple thing.
I'm trying to learn the process of integrating Swagger into an existing Dropwizard application to generate the API documentation, ideally using the Swagger UI interface so that it's interactive for people trying to use/learn it. Specifically, using this bundle: smoketurner/dropwizard-swagger
Before trying to wrestle with the full sized project my employer wants it integrated with, I tried adding it into the standard Dropwizard example application, thinking that should be a hassle-free jumping off point. After following the instructions on the github page for the bundle, I'm hit by the following error:
Test set: com.example.helloworld.IntegrationTest
-------------------------------------------------------------------------------
Tests run: 1, Failures: 0, Errors: 1, Skipped: 0, Time elapsed: 2.003 s <<< FAILURE! - in com.example.helloworld.IntegrationTest
com.example.helloworld.IntegrationTest Time elapsed: 2.003 s <<< ERROR!
java.lang.IllegalStateException: You need to provide an instance of SwaggerBundleConfiguration
What am I missing?
Below are the Configuration and Application files in question, with the additions made as per the github bundle instructions.
HelloWorldConfiguration:
package com.example.helloworld;
import com.example.helloworld.core.Template;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.google.common.collect.ImmutableMap;
import io.dropwizard.Configuration;
import io.dropwizard.db.DataSourceFactory;
import io.federecio.dropwizard.swagger.SwaggerBundleConfiguration;
import org.hibernate.validator.constraints.NotEmpty;
import javax.validation.Valid;
import javax.validation.constraints.NotNull;
import java.util.Collections;
import java.util.Map;
public class HelloWorldConfiguration extends Configuration {
#NotEmpty
private String template;
#NotEmpty
private String defaultName = "Stranger";
#JsonProperty("swagger")
public SwaggerBundleConfiguration swaggerBundleConfiguration;
#Valid
#NotNull
private DataSourceFactory database = new DataSourceFactory();
#NotNull
private Map<String, Map<String, String>> viewRendererConfiguration = Collections.emptyMap();
#JsonProperty
public String getTemplate() {
return template;
}
#JsonProperty
public void setTemplate(String template) {
this.template = template;
}
#JsonProperty
public String getDefaultName() {
return defaultName;
}
#JsonProperty
public void setDefaultName(String defaultName) {
this.defaultName = defaultName;
}
public Template buildTemplate() {
return new Template(template, defaultName);
}
#JsonProperty("database")
public DataSourceFactory getDataSourceFactory() {
return database;
}
#JsonProperty("database")
public void setDataSourceFactory(DataSourceFactory dataSourceFactory) {
this.database = dataSourceFactory;
}
#JsonProperty("viewRendererConfiguration")
public Map<String, Map<String, String>> getViewRendererConfiguration() {
return viewRendererConfiguration;
}
#JsonProperty("viewRendererConfiguration")
public void setViewRendererConfiguration(Map<String, Map<String, String>> viewRendererConfiguration) {
final ImmutableMap.Builder<String, Map<String, String>> builder = ImmutableMap.builder();
for (Map.Entry<String, Map<String, String>> entry : viewRendererConfiguration.entrySet()) {
builder.put(entry.getKey(), ImmutableMap.copyOf(entry.getValue()));
}
this.viewRendererConfiguration = builder.build();
}
}
HelloWorldApplication:
package com.example.helloworld;
import com.example.helloworld.auth.ExampleAuthenticator;
import com.example.helloworld.auth.ExampleAuthorizer;
import com.example.helloworld.cli.RenderCommand;
import com.example.helloworld.core.Person;
import com.example.helloworld.core.Template;
import com.example.helloworld.core.User;
import com.example.helloworld.db.PersonDAO;
import com.example.helloworld.filter.DateRequiredFeature;
import com.example.helloworld.health.TemplateHealthCheck;
import com.example.helloworld.resources.FilteredResource;
import com.example.helloworld.resources.HelloWorldResource;
import com.example.helloworld.resources.PeopleResource;
import com.example.helloworld.resources.PersonResource;
import com.example.helloworld.resources.ProtectedResource;
import com.example.helloworld.resources.ViewResource;
import com.example.helloworld.tasks.EchoTask;
import io.dropwizard.Application;
import io.dropwizard.assets.AssetsBundle;
import io.dropwizard.auth.AuthDynamicFeature;
import io.dropwizard.auth.AuthValueFactoryProvider;
import io.dropwizard.auth.basic.BasicCredentialAuthFilter;
import io.dropwizard.configuration.EnvironmentVariableSubstitutor;
import io.dropwizard.configuration.SubstitutingSourceProvider;
import io.dropwizard.db.DataSourceFactory;
import io.dropwizard.hibernate.HibernateBundle;
import io.dropwizard.migrations.MigrationsBundle;
import io.dropwizard.setup.Bootstrap;
import io.dropwizard.setup.Environment;
import io.dropwizard.views.ViewBundle;
import io.federecio.dropwizard.swagger.SwaggerBundle;
import io.federecio.dropwizard.swagger.SwaggerBundleConfiguration;
import org.glassfish.jersey.server.filter.RolesAllowedDynamicFeature;
import java.util.Map;
public class HelloWorldApplication extends Application<HelloWorldConfiguration> {
public static void main(String[] args) throws Exception {
new HelloWorldApplication().run(args);
}
private final HibernateBundle<HelloWorldConfiguration> hibernateBundle =
new HibernateBundle<HelloWorldConfiguration>(Person.class) {
#Override
public DataSourceFactory getDataSourceFactory(HelloWorldConfiguration configuration) {
return configuration.getDataSourceFactory();
}
};
#Override
public String getName() {
return "hello-world";
}
#Override
public void initialize(Bootstrap<HelloWorldConfiguration> bootstrap) {
// Enable variable substitution with environment variables
bootstrap.setConfigurationSourceProvider(
new SubstitutingSourceProvider(
bootstrap.getConfigurationSourceProvider(),
new EnvironmentVariableSubstitutor(false)
)
);
bootstrap.addCommand(new RenderCommand());
bootstrap.addBundle(new AssetsBundle());
bootstrap.addBundle(new MigrationsBundle<HelloWorldConfiguration>() {
#Override
public DataSourceFactory getDataSourceFactory(HelloWorldConfiguration configuration) {
return configuration.getDataSourceFactory();
}
});
bootstrap.addBundle(hibernateBundle);
bootstrap.addBundle(new ViewBundle<HelloWorldConfiguration>() {
#Override
public Map<String, Map<String, String>> getViewConfiguration(HelloWorldConfiguration configuration) {
return configuration.getViewRendererConfiguration();
}
});
bootstrap.addBundle(new SwaggerBundle<HelloWorldConfiguration>() {
#Override
protected SwaggerBundleConfiguration getSwaggerBundleConfiguration(HelloWorldConfiguration configuration) {
return configuration.swaggerBundleConfiguration;
}
});
}
#Override
public void run(HelloWorldConfiguration configuration, Environment environment) {
final PersonDAO dao = new PersonDAO(hibernateBundle.getSessionFactory());
final Template template = configuration.buildTemplate();
environment.healthChecks().register("template", new TemplateHealthCheck(template));
environment.admin().addTask(new EchoTask());
environment.jersey().register(DateRequiredFeature.class);
environment.jersey().register(new AuthDynamicFeature(new BasicCredentialAuthFilter.Builder<User>()
.setAuthenticator(new ExampleAuthenticator())
.setAuthorizer(new ExampleAuthorizer())
.setRealm("SUPER SECRET STUFF")
.buildAuthFilter()));
environment.jersey().register(new AuthValueFactoryProvider.Binder<>(User.class));
environment.jersey().register(RolesAllowedDynamicFeature.class);
environment.jersey().register(new HelloWorldResource(template));
environment.jersey().register(new ViewResource());
environment.jersey().register(new ProtectedResource());
environment.jersey().register(new PeopleResource(dao));
environment.jersey().register(new PersonResource(dao));
environment.jersey().register(new FilteredResource());
}
}
For anyone else trying to learn this and struggling, the issue was that the included test suite in the sample application has its own YML file, test-example.yml that you also need to add the swagger properties into. This will allow the tests to pass and everything should go smoothly from there.
Added properties to test-example.yml:
swagger:
resourcePackage: com.example.helloworld.resources

Spring MongoDB mapping OAuth2Authentication

I'm writing my own implementation of TokenStore (org.springframework.security.oauth2.provider.token.TokenStore) using MongoDB. There seems to be some problem with converting/mapping of the object in the database back to Java object.
Anyone have a clue how I could solve this?
org.springframework.data.mapping.model.MappingInstantiationException: Failed to instantiate org.springframework.security.authentication.UsernamePasswordAuthenticationToken using constructor NO_CONSTRUCTOR with arguments
at org.springframework.data.convert.ReflectionEntityInstantiator.createInstance(ReflectionEntityInstantiator.java:64) ~[spring-data-commons-1.11.0.RELEASE.jar:na]
at org.springframework.data.convert.ClassGeneratingEntityInstantiator.createInstance(ClassGeneratingEntityInstantiator.java:83) ~[spring-data-commons-1.11.0.RELEASE.jar:na]
at org.springframework.data.mongodb.core.convert.MappingMongoConverter.read(MappingMongoConverter.java:251) ~[spring-data-mongodb-1.8.0.RELEASE.jar:na]
at org.springframework.data.mongodb.core.convert.MappingMongoConverter.read(MappingMongoConverter.java:231) ~[spring-data-mongodb-1.8.0.RELEASE.jar:na]
at org.springframework.data.mongodb.core.convert.MappingMongoConverter.readValue(MappingMongoConverter.java:1185) ~[spring-data-mongodb-1.8.0.RELEASE.jar:na]
at org.springframework.data.mongodb.core.convert.MappingMongoConverter.access$200(MappingMongoConverter.java:78) ~[spring-data-mongodb-1.8.0.RELEASE.jar:na]
You need to create a converter and register it as Spring Mongo doesn't do this for you.
Create a converter
import com.erranda.abraham.entity.Person;
import com.mongodb.DBObject;
import org.springframework.core.convert.converter.Converter;
import org.springframework.data.convert.ReadingConverter;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.security.oauth2.provider.OAuth2Request;
import java.util.*;
/**
* #version 1.0
* #author: Iain Porter
* #since 23/05/2013
*/
//Hackery to deserialize back into an OAuth2Authentication Object made necessary because Spring Mongo can't map clientAuthentication to authorizationRequest
#ReadingConverter
#SuppressWarnings("rawtypes")
public class OAuth2AuthenticationReadConverter implements Converter<DBObject, OAuth2Authentication> {
#Override
#SuppressWarnings("unchecked")
public OAuth2Authentication convert(DBObject source) {
System.out.println(source);
DBObject storedRequest = (DBObject)source.get("storedRequest");
OAuth2Request oAuth2Request = new OAuth2Request((Map<String, String>)storedRequest.get("requestParameters"),
(String)storedRequest.get("clientId"), null, true, new HashSet((List)storedRequest.get("scope")),
null, null, null, null);
DBObject userAuthorization = (DBObject)source.get("userAuthentication");
Object principal = getPrincipalObject(userAuthorization.get("principal"));
Authentication userAuthentication = new UsernamePasswordAuthenticationToken(principal,
(String)userAuthorization.get("credentials"), getAuthorities((List) userAuthorization.get("authorities")));
OAuth2Authentication authentication = new OAuth2Authentication(oAuth2Request,
userAuthentication );
return authentication;
}
private Object getPrincipalObject(Object principal) {
if(principal instanceof DBObject) {
DBObject principalDBObject = (DBObject)principal;
Person user = new Person (principalDBObject);
return user;
} else {
return principal;
}
}
private Collection<GrantedAuthority> getAuthorities(List<Map<String, String>> authorities) {
Set<GrantedAuthority> grantedAuthorities = new HashSet<GrantedAuthority>(authorities.size());
for(Map<String, String> authority : authorities) {
grantedAuthorities.add(new SimpleGrantedAuthority(authority.get("role")));
}
return grantedAuthorities;
}
}
Then you need to register converter along side your mongodb configuration
import com.erranda.abraham.api.security.OAuth2AuthenticationReadConverter;
import com.mongodb.Mongo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.convert.converter.Converter;
import org.springframework.data.authentication.UserCredentials;
import org.springframework.data.mongodb.MongoDbFactory;
import org.springframework.data.mongodb.config.AbstractMongoConfiguration;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.SimpleMongoDbFactory;
import org.springframework.data.mongodb.core.convert.CustomConversions;
import org.springframework.data.mongodb.repository.config.EnableMongoRepositories;
import org.springframework.util.StringUtils;
import java.util.ArrayList;
import java.util.List;
#Configuration
public class MongoDbConfiguration extends AbstractMongoConfiguration {
private static final Logger LOG = LoggerFactory.getLogger(MongoDbConfiguration.class);
private static final String MONGO_DB_SERVER = "mongo.db.server";
private static final String MONGO_DB_PORT = "mongo.db.port";
private static final String MONGO_DB_NAME = "mongo.db.name";
private static final String MONGO_DB_LOGON = "mongo.db.logon";
private static final String MONGO_DB_PASSWORD = "mongo.db.password";
private static final String SPRING_PROFILES_ACTIVE = "spring.profiles.active";
#Autowired
private ApplicationContext applicationContext;
#Value("${" + MONGO_DB_SERVER + "}")
private String mongoServer;
#Value("${" + MONGO_DB_PORT + "}")
private int mongoPort;
#Value("${" + MONGO_DB_NAME + "}")
private String mongoDBName;
#Value("${" + MONGO_DB_LOGON + "}")
private String mongoDbLogin;
#Value("${" + MONGO_DB_PASSWORD + "}")
private String mongoDbPassword;
#Override
protected String getDatabaseName() {
return mongoDBName;
}
#Override
#Bean
public Mongo mongo() throws Exception {
return new Mongo(mongoServer, mongoPort);
}
#Override
#Bean
public MongoTemplate mongoTemplate() throws Exception {
if (!StringUtils.isEmpty(mongoDbLogin)) {
LOG.info("Configuring mongoTemplate with credentials.");
MongoDbFactory mongoDbFactory = new SimpleMongoDbFactory(mongo(), mongoDBName, new UserCredentials(mongoDbLogin, mongoDbPassword));
return new MongoTemplate(mongoDbFactory, mappingMongoConverter());
} else {
LOG.info("Configuring mongoTemplate without credentials.");
MongoDbFactory mongoDbFactory = new SimpleMongoDbFactory(mongo(), mongoDBName);
return new MongoTemplate(mongoDbFactory, mappingMongoConverter());
}
}
#Override
#Bean
public CustomConversions customConversions() {
List<Converter<?, ?>> converterList = new ArrayList<Converter<?, ?>>();
OAuth2AuthenticationReadConverter converter = new OAuth2AuthenticationReadConverter();
converterList.add(converter);
return new CustomConversions(converterList);
}
private String getContextProperty(final String propertyKey) {
return applicationContext.getEnvironment().getProperty(propertyKey);
}
}
Don't forget to mark as correct if it works for you.
Based on https://github.com/iainporter/oauth2-provider

How to add twitter capability to my struts2 application

I developed struts2 web application, now I want people to login from their twitter account, so I need to place a button called "Login with Twitter" under my normal login button. I already did Facebook integration so as far as my knowledge we need to create the application first in twitter so i did that then i am confused what to do, please anyone guide me through that steps.
I don't really recall the process of registering your application with twitter but google "Single-Sign-On (SSO) using twitter".
First you need to register your application, in doing so you will be given a consumer_key and a consumer_secret (not sure if those are twitters terms).
Then the process is to send the user to twitter using those credentials, have the user sign in and then have twitter return control back to your application with a callback. That callback will contain an authorization token, which will grant access to twitter services so we will save that in the session.
After you have registered your application the following code will perform login, and let you post the string "hello!" to your twitter account (Assuming the application has this privilege).
TwitterGrantAccess.java
package com.quaternion.demo.action.twitter;
import com.opensymphony.xwork2.ActionSupport;
import java.util.Map;
import org.apache.struts2.convention.annotation.Result;
import org.apache.struts2.convention.annotation.Results;
import org.apache.struts2.interceptor.SessionAware;
import org.scribe.builder.ServiceBuilder;
import org.scribe.builder.api.TwitterApi;
import org.scribe.model.Token;
import org.scribe.oauth.OAuthService;
#Results(value = {
#Result(name = "success", location = "${authorizationURL}", type = "redirect"),
#Result(name = "error", location = "/WEB-INF/content/error.jsp")
})
public class TwitterGrantAccess extends ActionSupport implements SessionAware {
private Map<String, Object> session;
private String authorizationURL = null;
#Override
public String execute() {
//Twitter twitter = new TwitterFactory().getInstance();
String consumer_key = "NOT_PUTTING_MY_KEY_ON_STACK_OVERFLOW!";
String consumer_secret = "NOT_PUTTING_MY_CONSUMER_SECRET_ON_STACK_OVERFLOW!";
OAuthService twitterService = new ServiceBuilder()
.provider(TwitterApi.class)
.apiKey(consumer_key)
.apiSecret(consumer_secret)
.callback("http://localhost:8080/demo/twitter/twitter-callback")
.build();
Token requestToken = twitterService.getRequestToken();
authorizationURL = twitterService.getAuthorizationUrl(requestToken);
session.put("twitterService", twitterService);
session.put("requestToken", requestToken);
return SUCCESS;
}
public String getAuthorizationURL() {
return this.authorizationURL;
}
#Override
public void setSession(Map<String, Object> map) {
this.session = map;
}
}
The Callback invoked by twitter (something you will not call as a user)...
TwitterCallback.java
package com.quaternion.demo.action.twitter;
import com.opensymphony.xwork2.ActionSupport;
import java.util.Map;
import org.apache.struts2.convention.annotation.Result;
import org.apache.struts2.convention.annotation.Results;
import org.apache.struts2.interceptor.SessionAware;
import org.scribe.model.Token;
import org.scribe.model.Verifier;
import org.scribe.oauth.OAuthService;
#Results(value = {
#Result(name = "success", location = "/WEB-INF/content/twitter/twitter-callback-success.jsp"),
#Result(name = "error", location = "/WEB-INF/content/twitter/twitter-callback-error.jsp")
})
public class TwitterCallback extends ActionSupport implements SessionAware {
private Map<String, Object> session;
private String key;
private String secret;
//returned from twitter
private String oauth_token;
private String oauth_verifier;
#Override
public String execute() {
if (session.containsKey("accessToken") && session.get("accessToken") != null) {
return SUCCESS; //accessToken already exists!
}
Token requestToken = (Token) session.get("requestToken");
if (objectToken == null) {
super.addActionError("requestToken is null");
return ERROR;
}
OAuthService twitterService = (OAuthService) session.get("twitterService");
System.out.println(requestToken.toString());
System.out.println(this.getOauth_verifier());
//Token accessToken = twitter.getOAuthAccessToken(requestToken, this.getOauth_verifier());
Token accessToken = twitterService.getAccessToken(requestToken, new Verifier(this.getOauth_verifier()));
session.put("accessToken", accessToken);
this.setKey(accessToken.getToken()); //just to see something happen
this.setSecret(accessToken.getSecret());//just to see something happen
return SUCCESS;
}
#Override
public void setSession(Map<String, Object> map) {
this.session = map;
}
/**
* #return the key
*/
public String getKey() {
return key;
}
/**
* #param key the key to set
*/
public void setKey(String key) {
this.key = key;
}
public String getSecret() {
return secret;
}
public void setSecret(String secret) {
this.secret = secret;
}
public String getOauth_token() {
return oauth_token;
}
/**
* #param oauth_token the oauth_token to set
*/
public void setOauth_token(String oauth_token) {
this.oauth_token = oauth_token;
}
public String getOauth_verifier() {
return oauth_verifier;
}
public void setOauth_verifier(String oauth_verifier) {
this.oauth_verifier = oauth_verifier;
}
}
With this done your application can now use the API, let's post a tweet:
Tweet.java
//Posts the string "hello!" to the users twitter feed then redirects to
//ken_mcwilliams twitter url, because that is the account I will be
//logging into... change you your own account during development
package com.quaternion.demo.action.twitter;
import com.opensymphony.xwork2.ActionSupport;
import java.util.Map;
import org.apache.struts2.convention.annotation.Result;
import org.apache.struts2.convention.annotation.Results;
import org.apache.struts2.interceptor.SessionAware;
import org.scribe.model.OAuthRequest;
import org.scribe.model.Response;
import org.scribe.model.Token;
import org.scribe.model.Verb;
import org.scribe.oauth.OAuthService;
#Results({
#Result(name = "success", location = "https://twitter.com/#!/ken_mcwilliams", type = "redirect")
})
public class Tweet extends ActionSupport implements SessionAware {
private Map<String, Object> session;
private String status;
#Override
public String execute() {
Token accessToken = (Token) session.get("accessToken");
OAuthService twitterService = (OAuthService) session.get("twitterService");
String url = "http://api.twitter.com/1/statuses/update.json?status=";
String twitterStatus;
if (status == null || status.isEmpty() == true) {
twitterStatus = "hello!";
}else{
twitterStatus = status;
}
OAuthRequest request = new OAuthRequest(Verb.POST, url + twitterStatus);
twitterService.signRequest(accessToken, request); // the access token from step 4
Response response = request.send();
return SUCCESS;
}
public void setStatus(String status) {
this.status = status;
}
public String getStatus() {
return this.status;
}
#Override
public void setSession(Map<String, Object> map) {
session = map;
}
}
PS: twitter-callback-success.jsp and twitter-callback-error.jsp don't contain anything interesting, they just state "You now have access to twitter and everything is great!" and "Something went horribly wrong".

How to use open Id in jsp

Hi I am trying to build a login system like Stack Overflow but not find the right way to do this in JSP. I am working in struts2.
The following illustrate Single Sign On (SSO) using Oauth, for which you can create a SSO system similar to that of Stack Overflow.
Use scribe: https://github.com/fernandezpablo85/scribe-java/wiki/getting-started
The following example will demonstrate using Twitter...
1) Demonstrate an action to get twitter credentials.
package com.quaternion.struts2basic.action;
import com.opensymphony.xwork2.ActionSupport;
import java.util.Map;
import org.apache.struts2.convention.annotation.Result;
import org.apache.struts2.convention.annotation.Results;
import org.apache.struts2.interceptor.SessionAware;
import org.scribe.builder.ServiceBuilder;
import org.scribe.builder.api.TwitterApi;
import org.scribe.model.Token;
import org.scribe.oauth.OAuthService;
#Results(value = {
#Result(name = "success", location = "${authorizationURL}", type = "redirect"),
#Result(name = "error", location = "/WEB-INF/content/error.jsp")
})
public class TwitterGrantAccess extends ActionSupport implements SessionAware {
private Map<String, Object> session;
private String authorizationURL = null;
#Override
public String execute() {
//Twitter twitter = new TwitterFactory().getInstance();
String consumer_key = "rUPV8tpIcFtyMeSDlnzclA";
String consumer_secret = "16omdjNoEYgwoXfZMc0XrXSxiHDaS0UZUxQzWhTFg";
OAuthService twitterService = new ServiceBuilder()
.provider(TwitterApi.class)
.apiKey(consumer_key)
.apiSecret(consumer_secret)
.callback("http://127.0.0.1:8080/Struts2Basic/twitter-callback")
.build();
Token requestToken = twitterService.getRequestToken();
authorizationURL = twitterService.getAuthorizationUrl(requestToken);
session.put("twitterService", twitterService);
session.put("requestToken", requestToken);
return SUCCESS;
}
public String getAuthorizationURL() {
return this.authorizationURL;
}
#Override
public void setSession(Map<String, Object> map) {
this.session = map;
}
}
2) Action which twitter redirects back to...
package com.quaternion.struts2basic.action;
import com.opensymphony.xwork2.ActionSupport;
import java.util.Map;
import org.apache.struts2.convention.annotation.Result;
import org.apache.struts2.convention.annotation.Results;
import org.apache.struts2.interceptor.SessionAware;
import org.scribe.model.Token;
import org.scribe.model.Verifier;
import org.scribe.oauth.OAuthService;
#Results(value = {
#Result(name = "success", location = "/WEB-INF/content/twitter-callback-success.jsp"),
#Result(name = "error", location = "/WEB-INF/content/error.jsp")
})
public class TwitterCallback extends ActionSupport implements SessionAware {
private Map<String, Object> session;
private String key;
private String secret;
//returned from twitter
private String oauth_token;
private String oauth_verifier;
#Override
public String execute() {
if (session.containsKey("accessToken") && session.get("accessToken") != null) {
return SUCCESS; //accessToken already exists!
}
Token requestToken = (Token) session.get("requestToken");
if (requestToken == null) {
super.addActionError("requestToken is null");
return ERROR;
}
OAuthService twitterService = (OAuthService) session.get("twitterService");
System.out.println(requestToken.toString());
System.out.println(this.getOauth_verifier());
//Token accessToken = twitter.getOAuthAccessToken(requestToken, this.getOauth_verifier());
Token accessToken = twitterService.getAccessToken(requestToken, new Verifier(this.getOauth_verifier()));
session.put("accessToken", accessToken);
this.setKey(accessToken.getToken()); //just to see something happen
this.setSecret(accessToken.getSecret());//just to see something happen
return SUCCESS;
}
#Override
public void setSession(Map<String, Object> map) {
this.session = map;
}
public String getKey() {
return key;
}
public void setKey(String key) {
this.key = key;
}
public String getSecret() {
return secret;
}
public void setSecret(String secret) {
this.secret = secret;
}
public String getOauth_token() {
return oauth_token;
}
public void setOauth_token(String oauth_token) {
this.oauth_token = oauth_token;
}
public String getOauth_verifier() {
return oauth_verifier;
}
public void setOauth_verifier(String oauth_verifier) {
this.oauth_verifier = oauth_verifier;
}
}
I'll omit the views because they really don't do anything
3) An action which writes "Hello from Struts2!", which isn't very good because twitter will only let you run this once and because the status is the same will not let you post it again... but it gets the process across. After updating the status it redirects to your twitter page, if you change the "YOUR_USER_NAME" part of the url in the redirect of course.
package com.quaternion.struts2basic.action;
import com.opensymphony.xwork2.ActionSupport;
import java.util.Map;
import org.apache.struts2.convention.annotation.Result;
import org.apache.struts2.convention.annotation.Results;
import org.apache.struts2.interceptor.SessionAware;
import org.scribe.model.OAuthRequest;
import org.scribe.model.Response;
import org.scribe.model.Token;
import org.scribe.model.Verb;
import org.scribe.oauth.OAuthService;
#Results({
#Result(name = "success", location = "https://twitter.com/#!/YOUR_USER_NAME", type = "redirect")
})
public class Tweet extends ActionSupport implements SessionAware {
private Map<String, Object> session;
private String status;
#Override
public String execute() {
Token accessToken = (Token) session.get("accessToken");
OAuthService twitterService = (OAuthService) session.get("twitterService");
String url = "http://api.twitter.com/1/statuses/update.json?status=";
String twitterStatus = "hello!";
OAuthRequest request = new OAuthRequest(Verb.POST, url + twitterStatus);
twitterService.signRequest(accessToken, request);
Response response = request.send();
return SUCCESS;
}
public void setStatus(String status) {
this.status = status;
}
public String getStatus() {
return this.status;
}
#Override
public void setSession(Map<String, Object> map) {
session = map;
}
}
That is pretty much it. The nice things about scribe is it is so easy to configure for the different providers (for basic authentication, using their APIs after is another matter and that is up to you).
It dependents upon how you want to build it.There are certain number of library which you can use to build you login system and few of them are
Joid
openid4java
Here is a outline what all you have to do in order to make the complete flow
Create a JSP page where use can select a way to choose his login system.
Call an action class which Create an authentication request for this identifier.
Redirect user to the OpenId service provider and let him authorize themself.
Receive the OpenID Provider's authentication response at your callback action.
parse the response if you need to store some information.

Resources