package org.atricore.idbus.capabilities.openidconnect.main.proxy.producers; import com.google.api.client.auth.oauth.OAuthCallbackUrl; import com.google.api.client.auth.oauth.OAuthCredentialsResponse; import com.google.api.client.auth.oauth.OAuthGetAccessToken; import com.google.api.client.auth.oauth.OAuthHmacSigner; import com.google.api.client.auth.oauth2.AuthorizationCodeResponseUrl; import com.google.api.client.http.GenericUrl; import com.google.api.services.oauth2.model.Userinfoplus; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.atricore.idbus.capabilities.openidconnect.main.binding.OpenIDConnectBinding; import org.atricore.idbus.capabilities.openidconnect.main.common.OpenIDConnectConstants; import org.atricore.idbus.capabilities.openidconnect.main.common.OpenIDConnectException; import org.atricore.idbus.capabilities.openidconnect.main.common.oauth.OAuthGetAccessTokenUsingPost; import org.atricore.idbus.capabilities.openidconnect.main.proxy.OpenIDConnectProxyMediator; import org.atricore.idbus.capabilities.sso.support.auth.AuthnCtxClass; import org.atricore.idbus.capabilities.sso.support.core.NameIDFormat; import org.atricore.idbus.common.sso._1_0.protocol.*; import org.atricore.idbus.kernel.main.federation.metadata.EndpointDescriptor; import org.atricore.idbus.kernel.main.federation.metadata.EndpointDescriptorImpl; import org.atricore.idbus.kernel.main.mediation.IdentityMediationException; import org.atricore.idbus.kernel.main.mediation.MediationMessageImpl; import org.atricore.idbus.kernel.main.mediation.MediationState; import org.atricore.idbus.kernel.main.mediation.camel.AbstractCamelEndpoint; import org.atricore.idbus.kernel.main.mediation.camel.component.binding.CamelMediationExchange; import org.atricore.idbus.kernel.main.mediation.camel.component.binding.CamelMediationMessage; import org.atricore.idbus.kernel.main.util.UUIDGenerator; import twitter4j.Twitter; import twitter4j.TwitterFactory; import twitter4j.User; import twitter4j.conf.ConfigurationBuilder; import java.util.ArrayList; import java.util.List; public class TwitterAuthzTokenConsumerProducer extends AuthzTokenConsumerProducer { private static final Log logger = LogFactory.getLog(TwitterAuthzTokenConsumerProducer.class); protected UUIDGenerator uuidGenerator = new UUIDGenerator(); public TwitterAuthzTokenConsumerProducer(AbstractCamelEndpoint<CamelMediationExchange> endpoint) throws Exception { super(endpoint); } @Override protected void doProcess(CamelMediationExchange exchange) throws Exception { CamelMediationMessage in = (CamelMediationMessage) exchange.getIn(); if (in.getMessage().getContent() instanceof OAuthCallbackUrl) { if (logger.isTraceEnabled()) logger.trace("Processing OAuthCallback"); OAuthCallbackUrl oauthCallback = (OAuthCallbackUrl) in.getMessage().getContent(); doProcessOAuthCallbackResponse(exchange, oauthCallback); } else { throw new IdentityMediationException("Unknown message type " + in.getMessage().getContent()); } } @Override protected void doProcessAuthzTokenResponse(CamelMediationExchange exchange, AuthorizationCodeResponseUrl authnResp) throws Exception { } protected void doProcessOAuthCallbackResponse(CamelMediationExchange exchange, OAuthCallbackUrl authnResp ) throws Exception { CamelMediationMessage in = (CamelMediationMessage) exchange.getIn(); CamelMediationMessage out = (CamelMediationMessage) exchange.getOut(); MediationState mediationState = in.getMessage().getState(); OpenIDConnectProxyMediator mediator = (OpenIDConnectProxyMediator) channel.getIdentityMediator(); // OAuth authorization response String token = authnResp.token; String verifier = authnResp.verifier; if (token == null) { logger.error("Missing oauth token"); throw new OpenIDConnectException("Illegal response, no oauth token received"); } else if (verifier == null) { logger.error("Missing oauth verifier"); throw new OpenIDConnectException("Illegal response, no oauth verifier received"); } OAuthHmacSigner signer = (OAuthHmacSigner) mediationState.getLocalVariable("urn:OPENID-CONNECT:1.0:signer"); String requestToken = (String) mediationState.getLocalVariable("urn:OPENID-CONNECT:1.0:requestToken"); // Validate request token if (!token.equals(requestToken)) { logger.error("Received token doesn't match original request token"); throw new OpenIDConnectException("Illegal response, request tokens mismatch"); } // Validate relay state String expectedRelayState = (String) mediationState.getLocalVariable("urn:OPENID-CONNECT:1.0:relayState"); ArrayList relayState = (ArrayList) authnResp.get("state"); if (relayState == null || relayState.size() == 0 || !expectedRelayState.equals(relayState.get(0))) { // Invalid response if (logger.isDebugEnabled()) logger.debug("Invalid state [" + relayState + "], expected [" + expectedRelayState + "]"); throw new OpenIDConnectException("Illegal response, received OpenID Connect state is not valid"); } // --------------------------------------------------------------- // Request access token // --------------------------------------------------------------- OAuthGetAccessToken accessTokenRequest = new OAuthGetAccessTokenUsingPost(mediator.getAccessTokenServiceLocation()); accessTokenRequest.consumerKey = mediator.getClientId(); accessTokenRequest.signer = signer; accessTokenRequest.transport = mediator.getHttpTransport(); accessTokenRequest.temporaryToken = token; accessTokenRequest.verifier = verifier; OAuthCredentialsResponse accessTokenResponse = accessTokenRequest.execute(); String accessToken = accessTokenResponse.token; String accessTokenSecret = accessTokenResponse.tokenSecret; if (logger.isTraceEnabled()) logger.trace("Access token [" + accessToken + "]"); // Get user profile ConfigurationBuilder confBuilder = new ConfigurationBuilder(); confBuilder.setOAuthConsumerKey(mediator.getClientId()); confBuilder.setOAuthConsumerSecret(mediator.getClientSecret()); confBuilder.setOAuthAccessToken(accessToken); confBuilder.setOAuthAccessTokenSecret(accessTokenSecret); TwitterFactory factory = new TwitterFactory(confBuilder.build()); Twitter twitter = factory.getInstance(); User user = twitter.verifyCredentials(); SubjectType subject; List<SubjectAttributeType> attrs = new ArrayList<SubjectAttributeType>(); subject = new SubjectType(); SubjectNameIDType a = new SubjectNameIDType(); a.setName(user.getName()); a.setFormat(NameIDFormat.UNSPECIFIED.getValue()); a.setLocalName(user.getName()); a.setNameQualifier(getFederatedProvider().getName().toUpperCase()); a.setLocalNameQualifier(getFederatedProvider().getName().toUpperCase()); subject.getAbstractPrincipal().add(a); SubjectAttributeType accessTokenAttr = new SubjectAttributeType(); accessTokenAttr.setName("accessToken"); accessTokenAttr.setValue(accessToken); attrs.add(accessTokenAttr); SubjectAttributeType accessTokenSecretAttr = new SubjectAttributeType(); accessTokenSecretAttr.setName("accessTokenSecret"); accessTokenSecretAttr.setValue(accessTokenSecret); attrs.add(accessTokenSecretAttr); SubjectAttributeType accessTokenExpiresInAttr = new SubjectAttributeType(); accessTokenExpiresInAttr.setName("accessTokenExpiresIn"); accessTokenExpiresInAttr.setValue("0"); // Twitter access tokens do not expire attrs.add(accessTokenExpiresInAttr); SubjectAttributeType openIdSubjectAttr = new SubjectAttributeType(); openIdSubjectAttr.setName("openIdSubject"); openIdSubjectAttr.setValue(String.valueOf(user.getId())); attrs.add(openIdSubjectAttr); SubjectAttributeType authnCtxClassAttr = new SubjectAttributeType(); authnCtxClassAttr.setName("authnCtxClass"); authnCtxClassAttr.setValue(AuthnCtxClass.PPT_AUTHN_CTX.getValue()); attrs.add(authnCtxClassAttr); addUserAttributes(user, attrs); SPAuthnResponseType ssoResponse = new SPAuthnResponseType(); ssoResponse.setID(uuidGenerator.generateId()); ssoResponse.setIssuer(getFederatedProvider().getName()); SPInitiatedAuthnRequestType ssoRequest = (SPInitiatedAuthnRequestType) in.getMessage().getState(). getLocalVariable("urn:org:atricore:idbus:sso:protocol:SPInitiatedAuthnRequest"); if (ssoRequest != null) { ssoResponse.setInReplayTo(ssoRequest.getID()); } ssoResponse.setSessionIndex(uuidGenerator.generateId()); ssoResponse.setSubject(subject); ssoResponse.getSubjectAttributes().addAll(attrs); // ------------------------------------------------------------------------------ // Send SP Authentication response // ------------------------------------------------------------------------------ SPInitiatedAuthnRequestType authnRequest = (SPInitiatedAuthnRequestType) mediationState.getLocalVariable("urn:OPENID-CONNECT:1.0:authnRequest"); // Send response back String destinationLocation = resolveSpProxyACS(authnRequest); if (logger.isTraceEnabled()) logger.trace("Sending response to " + destinationLocation); EndpointDescriptor destination = new EndpointDescriptorImpl("EmbeddedSPAcs", "AssertionConsumerService", OpenIDConnectBinding.SSO_ARTIFACT.getValue(), destinationLocation, null); out.setMessage(new MediationMessageImpl(ssoResponse.getID(), ssoResponse, "SPAuthnResponse", "", destination, in.getMessage().getState())); exchange.setOut(out); return; } private void addUserAttributes(User user, List<SubjectAttributeType> attrs) { addUserAttribute(FIRST_NAME_USER_ATTR_NAME, user.getName(), attrs); addUserAttribute(COMMON_NAME_USER_ATTR_NAME, user.getScreenName(), attrs); addUserAttribute(LANGUAGE_USER_ATTR_NAME, user.getLang(), attrs); addUserAttribute(PICTURE_USER_ATTR_NAME, user.getProfileImageURL(), attrs); addUserAttribute(IS_VERIFIED_USER_ATTR_NAME, String.valueOf(user.isVerified()), attrs); } }