FEDIZ-172 - OIDC DataProvider should support client_credentials clients
diff --git a/services/oidc/src/main/java/org/apache/cxf/fediz/service/oidc/OAuthDataProviderImpl.java b/services/oidc/src/main/java/org/apache/cxf/fediz/service/oidc/OAuthDataProviderImpl.java
index 16bd697..43bd6de 100644
--- a/services/oidc/src/main/java/org/apache/cxf/fediz/service/oidc/OAuthDataProviderImpl.java
+++ b/services/oidc/src/main/java/org/apache/cxf/fediz/service/oidc/OAuthDataProviderImpl.java
@@ -21,7 +21,16 @@
 import java.security.Principal;
 import java.util.Collections;
 import java.util.List;
+import java.util.logging.Level;
+import java.util.logging.Logger;
 
+import javax.security.auth.callback.CallbackHandler;
+import javax.security.auth.login.Configuration;
+import javax.security.auth.login.LoginContext;
+import javax.security.auth.login.LoginException;
+
+import org.apache.cxf.common.logging.LogUtils;
+import org.apache.cxf.interceptor.security.NamePasswordCallbackHandler;
 import org.apache.cxf.rs.security.oauth2.common.Client;
 import org.apache.cxf.rs.security.oauth2.common.OAuthPermission;
 import org.apache.cxf.rs.security.oauth2.grants.code.DefaultEHCacheCodeDataProvider;
@@ -31,7 +40,12 @@
 
 public class OAuthDataProviderImpl extends DefaultEHCacheCodeDataProvider {
     
+    private static final Logger LOG = LogUtils.getL7dLogger(OAuthDataProviderImpl.class);
+    
     private boolean checkOnlyRegisteredClients;
+    private String contextName;
+    private Configuration loginConfig;
+
     
     @Override
     public Client getClient(String clientId) {
@@ -76,13 +90,44 @@
     }
     
     protected Client authenticateClient(String clientId, String clientSecret) {
-        // If the authentication is successful: 
-        // return new Client(clientId, clientSecret, true)
+        if (contextName != null) {
+            try {
+                // Login using JAAS
+                CallbackHandler callbackHandler = 
+                    new NamePasswordCallbackHandler(clientId, clientSecret);
+                LoginContext ctx = new LoginContext(getContextName(), null, callbackHandler, loginConfig);  
+                ctx.login();
+                Client client = new Client(clientId, clientSecret, true);
+                client.setAllowedGrantTypes(Collections.singletonList(OAuthConstants.CLIENT_CREDENTIALS_GRANT));
+                ctx.logout();
+                return client;
+            } catch (LoginException ex) {
+                ex.printStackTrace();
+                String errorMessage = "Authentication failed: " + ex.getMessage();
+                LOG.log(Level.FINE, errorMessage, ex);
+            }
+        }
         return null;
     }
 
     public void setCheckOnlyRegisteredClients(boolean checkOnlyRegisteredClients) {
         this.checkOnlyRegisteredClients = checkOnlyRegisteredClients;
     }
+    
+    public String getContextName() {
+        return contextName;
+    }
+
+    public void setContextName(String contextName) {
+        this.contextName = contextName;
+    }
+
+    public Configuration getLoginConfig() {
+        return loginConfig;
+    }
+
+    public void setLoginConfig(Configuration loginConfig) {
+        this.loginConfig = loginConfig;
+    }
 
 }
diff --git a/systests/oidc/pom.xml b/systests/oidc/pom.xml
index 5639f37..57f3e69 100644
--- a/systests/oidc/pom.xml
+++ b/systests/oidc/pom.xml
@@ -99,6 +99,16 @@
             <version>${cxf.version}</version>
             <scope>test</scope>
         </dependency>
+        <dependency>
+	        <groupId>org.apache.cxf</groupId>
+	        <artifactId>cxf-rt-ws-security</artifactId>
+	        <version>${cxf.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.cxf</groupId>
+            <artifactId>cxf-rt-ws-policy</artifactId>
+            <version>${cxf.version}</version>
+        </dependency>
     </dependencies>
     <build>
         <testResources>
@@ -197,6 +207,17 @@
                             </artifactItems>
                         </configuration>
                     </execution>
+                    <execution>
+                        <id>copy-extra-jars-to-oidc</id>
+                        <phase>package</phase>
+                        <goals>
+                          <goal>copy-dependencies</goal>
+                        </goals>
+                        <configuration>
+                            <outputDirectory>${basedir}/target/tomcat/rp/webapps/fediz-oidc/WEB-INF/lib</outputDirectory>
+                             <includeScope>compile</includeScope>
+                        </configuration>
+                    </execution>
                 </executions>
             </plugin>
             <plugin>
@@ -222,6 +243,26 @@
                             </resources>              
                         </configuration>            
                     </execution>
+                    <execution>
+                        <id>copy-entities-to-oidc</id>
+                        <phase>generate-test-sources</phase>
+                        <goals>
+                            <goal>copy-resources</goal>
+                        </goals>
+                        <configuration>
+                            <outputDirectory>${basedir}/target/tomcat/rp/webapps/fediz-oidc/WEB-INF</outputDirectory>
+                            <resources>          
+                                <resource>
+                                    <directory>${basedir}/src/test/resources/oidc</directory>
+                                    <includes>
+                                        <include>applicationContext.xml</include>
+                                        <include>data-manager.xml</include>
+                                    </includes>
+                                    <filtering>true</filtering>
+                                </resource>
+                            </resources>              
+                        </configuration>            
+                    </execution>
                 </executions>
             </plugin>
             <plugin>
@@ -261,6 +302,7 @@
                                 <idp.https.port>${idp.https.port}</idp.https.port>
                                 <rp.https.port>${rp.https.port}</rp.https.port>
                                 <java.io.tmpdir>${basedir}/target</java.io.tmpdir>
+                                <java.security.auth.login.config>src/test/resources/sts.jaas</java.security.auth.login.config>
                             </systemPropertyVariables>
                             <includes>
                                 <include>**/systests/**</include>
diff --git a/systests/oidc/src/test/java/org/apache/cxf/fediz/systests/oidc/OIDCTest.java b/systests/oidc/src/test/java/org/apache/cxf/fediz/systests/oidc/OIDCTest.java
index ccb3bc9..627e44e 100644
--- a/systests/oidc/src/test/java/org/apache/cxf/fediz/systests/oidc/OIDCTest.java
+++ b/systests/oidc/src/test/java/org/apache/cxf/fediz/systests/oidc/OIDCTest.java
@@ -632,6 +632,27 @@
         webClient.close();
     }
     
+    @org.junit.Test
+    public void testClientCredentialsSTS() throws Exception {
+        String url = "https://localhost:" + getRpHttpsPort() + "/fediz-oidc/oauth2/token";
+        WebRequest request = new WebRequest(new URL(url), HttpMethod.POST);
+
+        request.setRequestParameters(new ArrayList<NameValuePair>());
+        request.getRequestParameters().add(new NameValuePair("client_id", "alice"));
+        request.getRequestParameters().add(new NameValuePair("client_secret", "ecila"));
+        request.getRequestParameters().add(new NameValuePair("grant_type", "client_credentials"));
+        
+        final WebClient webClient = new WebClient();
+        webClient.getOptions().setUseInsecureSSL(true);
+        webClient.getOptions().setJavaScriptEnabled(false);
+        final UnexpectedPage responsePage = webClient.getPage(request);
+        String response = responsePage.getWebResponse().getContentAsString();
+
+        Assert.assertTrue(response.contains("access_token"));
+        
+        webClient.close();
+    }
+    
     private static WebClient setupWebClient(String user, String password, String idpPort) {
         final WebClient webClient = new WebClient();
         webClient.getOptions().setUseInsecureSSL(true);
diff --git a/systests/oidc/src/test/resources/oidc/applicationContext.xml b/systests/oidc/src/test/resources/oidc/applicationContext.xml
new file mode 100644
index 0000000..2eefe27
--- /dev/null
+++ b/systests/oidc/src/test/resources/oidc/applicationContext.xml
@@ -0,0 +1,230 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  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.
+-->
+<beans xmlns="http://www.springframework.org/schema/beans"
+	xmlns:cxf="http://cxf.apache.org/core"
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xmlns:jaxrs="http://cxf.apache.org/jaxrs" 
+    xmlns:util="http://www.springframework.org/schema/util"
+    xmlns:http="http://cxf.apache.org/transports/http/configuration"
+    xmlns:sec="http://cxf.apache.org/configuration/security"
+    xsi:schemaLocation="
+        http://cxf.apache.org/core
+        http://cxf.apache.org/schemas/core.xsd
+		http://www.springframework.org/schema/beans
+        http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
+        http://cxf.apache.org/jaxrs
+        http://cxf.apache.org/schemas/jaxrs.xsd
+        http://www.springframework.org/schema/util 
+        http://www.springframework.org/schema/util/spring-util.xsd
+        http://cxf.apache.org/transports/http/configuration
+        http://cxf.apache.org/schemas/configuration/http-conf.xsd
+        http://cxf.apache.org/configuration/security
+        http://cxf.apache.org/schemas/configuration/security.xsd">
+
+	<cxf:bus>
+        <cxf:features>
+            <cxf:logging/>
+        </cxf:features>
+    </cxf:bus>
+		
+    <import resource="data-manager.xml" />
+    
+    <!-- Supports OIDC Authorization Code flow -->
+    <bean id="oidcAuthorizationService" class="org.apache.cxf.rs.security.oidc.idp.OidcAuthorizationCodeService">
+         <property name="dataProvider" ref="oauthProvider"/>
+         <property name="subjectCreator" ref="subjectCreator"/>
+         <property name="skipAuthorizationWithOidcScope" value="true"/>
+         <!--
+         <property name="useAllClientScopes" value="true"/>
+         -->
+         <property name="canSupportPublicClients" value="true"/>
+    </bean>
+    <!-- Supports OIDC Implicit and Hybrid flows -->
+    <bean id="oidcHybridService" class="org.apache.cxf.rs.security.oidc.idp.OidcHybridService">
+         <property name="dataProvider" ref="oauthProvider"/>
+         <property name="subjectCreator" ref="subjectCreator"/>
+         <property name="skipAuthorizationWithOidcScope" value="true"/>
+         <property name="responseFilter" ref="idTokenFilter"/>
+         <property name="codeService" ref="oidcAuthorizationService"/>
+    </bean>
+    
+    <util:list id="oidcServices">
+        <ref bean="oidcAuthorizationService"/>
+        <ref bean="oidcHybridService"/>
+    </util:list>
+    
+    <!-- Service which makes Code, Implicit and Hybrid flow available 
+         at the same relative "/authorize" address -->
+    <bean id="authorizationService" class="org.apache.cxf.rs.security.oauth2.services.AuthorizationService">
+         <property name="services" ref="oidcServices"/>
+    </bean>
+    
+    <!-- Service supporting all OIDC Core flows -->
+    <jaxrs:server address="/idp">
+        <jaxrs:serviceBeans>
+           <ref bean="authorizationService"/>
+        </jaxrs:serviceBeans>
+        <jaxrs:providers>
+            <ref bean="viewProvider"/>
+            <ref bean="oauthJsonProvider"/>
+        </jaxrs:providers>
+        <jaxrs:properties>
+            <entry key="rs.security.signature.properties" value="rs.security.properties"/>
+            <entry key="rs.security.signature.key.password.provider" value-ref="keyPasswordProvider"/>
+        </jaxrs:properties>
+    </jaxrs:server>
+    
+    <!-- 
+         Public JWK Key Service: Disable it if the client secret is used or if 
+         pre-installing public OIDC keys to clients is preferred
+    --> 
+    <bean id="oidcKeysService" class="org.apache.cxf.rs.security.oidc.idp.OidcKeysService"/>
+    <jaxrs:server address="/jwk">
+        <jaxrs:serviceBeans>
+           <ref bean="oidcKeysService"/>
+        </jaxrs:serviceBeans>
+        <jaxrs:providers>
+            <bean class="org.apache.cxf.rs.security.jose.jaxrs.JsonWebKeysProvider"/>
+        </jaxrs:providers>
+        <jaxrs:properties>
+            <entry key="rs.security.signature.properties" value="rs.security.properties"/>
+            <entry key="rs.security.signature.key.password.provider" value-ref="keyPasswordProvider"/>
+        </jaxrs:properties>
+    </jaxrs:server>
+    
+    
+    <bean id="oauth2TokenValidationFilter" class="org.apache.cxf.rs.security.oauth2.filters.OAuthRequestFilter">
+         <property name="dataProvider" ref="oauthProvider"/>
+         <property name="audienceIsEndpointAddress" value="false"/>
+    </bean>
+     
+    <!-- User Info Service --> 
+    <bean id="userInfoService" class="org.apache.cxf.rs.security.oidc.idp.UserInfoService">
+        <property name="oauthDataProvider" ref="oauthProvider"/>
+        <property name="jwsRequired" value="false"/>
+    </bean>
+    <jaxrs:server address="/users">
+        <jaxrs:serviceBeans>
+           <ref bean="userInfoService"/>
+        </jaxrs:serviceBeans>
+        <jaxrs:providers>
+            <bean class="org.apache.cxf.jaxrs.provider.json.JsonMapObjectProvider"/>
+            <ref bean="oauth2TokenValidationFilter"/>
+        </jaxrs:providers>
+    </jaxrs:server>
+    
+    <bean id="keyPasswordProvider" class="org.apache.cxf.fediz.service.oidc.PrivateKeyPasswordProviderImpl"/>
+    
+    <!-- Client Registration Service -->
+    <bean id="clientRegService" init-method="init" 
+       class="org.apache.cxf.fediz.service.oidc.clients.ClientRegistrationService">
+       <property name="dataProvider" ref="oauthProvider"/>
+       <property name="clientProvider" ref="oauthProvider"/>
+       <!-- 
+           <property name="clientScopes" ref="supportedScopes"/>
+       -->
+       <property name="homeRealms">
+          <map>
+            <entry key="urn:org:apache:cxf:fediz:idp:realm-A" value="IDP of Realm A" />
+            <entry key="urn:org:apache:cxf:fediz:idp:realm-B" value="IDP of Realm B" />
+          </map>
+       </property>
+    </bean>
+    
+    <!-- Console linking to the client registration service -->
+    <bean id="consoleService" class="org.apache.cxf.fediz.service.oidc.console.UserConsoleService">
+        <property name="clientRegService" ref="clientRegService"/>
+    </bean>
+    <jaxrs:server address="/console">
+        <jaxrs:serviceBeans>
+            <ref bean="consoleService"/>
+        </jaxrs:serviceBeans>
+        <jaxrs:providers>
+            <ref bean="viewProvider"/>
+        </jaxrs:providers> 
+    </jaxrs:server>
+    
+    <bean id="viewProvider" class="org.apache.cxf.jaxrs.provider.RequestDispatcherProvider">
+       <property name="useClassNames" value="true"/>
+       <property name="locationPrefix" value="/WEB-INF/views/"/>
+       <property name="beanName" value="data"/>
+       <property name="dispatcherName" value="jsp"/>
+       <property name="resourcePaths">
+            <map>
+              <entry key="/remove" value="/WEB-INF/views/registeredClients.jsp"/>
+            </map>
+       </property>
+       <property name="classResources">
+            <map>
+              <entry key="org.apache.cxf.fediz.service.oidc.clients.InvalidRegistration" value="/WEB-INF/views/invalidRegistration.jsp"/>
+            </map>
+       </property>
+    </bean>
+    
+    <!-- AccessTokenService response filter which adds IdTokens to client responses -->
+    <bean id="idTokenFilter" class="org.apache.cxf.rs.security.oidc.idp.IdTokenResponseFilter">
+      <!--
+        <property name="signWithClientSecret" value="true"/>
+      -->
+    </bean>
+    <bean id="refreshTokenHandler" class="org.apache.cxf.rs.security.oauth2.grants.refresh.RefreshTokenGrantHandler">
+        <property name="dataProvider" ref="oauthProvider"/>
+    </bean>
+     <bean id="clientCredsHandler" class="org.apache.cxf.rs.security.oauth2.grants.clientcred.ClientCredentialsGrantHandler">
+        <property name="dataProvider" ref="oauthProvider"/>
+    </bean>
+    <!-- Access Token service -->
+    <bean id="accessTokenService" class="org.apache.cxf.rs.security.oauth2.services.AccessTokenService">
+        <property name="dataProvider" ref="oauthProvider"/>
+        <property name="responseFilter" ref="idTokenFilter"/>
+        <property name="grantHandler" ref="clientCredsHandler"/>
+        <property name="canSupportPublicClients" value="true"/>
+    </bean>
+    <!-- Access Token Introspection service -->
+    <bean id="accessTokenIntrospectionService" class="org.apache.cxf.rs.security.oauth2.services.TokenIntrospectionService">
+        <property name="dataProvider" ref="oauthProvider"/>
+        <property name="blockUnauthorizedRequests" value="false"/> 
+    </bean>
+    <bean id="oauthJsonProvider" class="org.apache.cxf.rs.security.oauth2.provider.OAuthJSONProvider"/>
+    <jaxrs:server address="/oauth2">
+        <jaxrs:serviceBeans>
+            <ref bean="accessTokenService"/>
+            <ref bean="accessTokenIntrospectionService"/>
+        </jaxrs:serviceBeans>
+        <jaxrs:providers>
+           <ref bean="oauthJsonProvider"/>
+        </jaxrs:providers>
+        <jaxrs:properties>
+            <entry key="rs.security.signature.properties" value="rs.security.properties"/>
+            <entry key="rs.security.signature.key.password.provider" value-ref="keyPasswordProvider"/>
+        </jaxrs:properties>
+     </jaxrs:server>
+     
+     <http:conduit name="*.http-conduit">
+        <http:tlsClientParameters
+            disableCNCheck="true">
+            <sec:trustManagers>
+                <sec:keyStore type="jks" password="tompass" resource="server.jks" />
+            </sec:trustManagers>
+        </http:tlsClientParameters>
+    </http:conduit>
+     
+</beans>
+
diff --git a/systests/oidc/src/test/resources/oidc/data-manager.xml b/systests/oidc/src/test/resources/oidc/data-manager.xml
new file mode 100644
index 0000000..3397962
--- /dev/null
+++ b/systests/oidc/src/test/resources/oidc/data-manager.xml
@@ -0,0 +1,87 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  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.
+-->
+<beans xmlns="http://www.springframework.org/schema/beans"
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xmlns:util="http://www.springframework.org/schema/util"
+    xsi:schemaLocation="
+        http://www.springframework.org/schema/beans
+        http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
+        http://www.springframework.org/schema/util 
+        http://www.springframework.org/schema/util/spring-util.xsd
+        ">
+    
+    <bean id="applicationContextProvider" class="org.apache.cxf.fediz.service.oidc.handler.hrd.ApplicationContextProvider"/>
+
+    <!-- List of accepted scopes -->
+    <util:map id="supportedScopes">
+        <entry key="openid" value="Access the authentication claims" />
+        <entry key="refreshToken" value="Refresh access tokens" />
+    </util:map>
+    
+    <!-- 
+        List of required scopes that must be available in request URIs when
+        client redirects users to OIDC
+    -->
+    <util:list id="coreScopes">
+        <value>openid</value>
+    </util:list>
+    
+    <!-- 
+        Typically the scopes authorized by the user will be reported back to the client,
+        reporting an approved refreshToken scope is currently disabled  
+    -->
+    <util:list id="invisibleToClientScopes">
+        <value>refreshToken</value>
+    </util:list>
+    
+    <!-- 
+        To support the alternative data persistence strategies: either register a custom
+        AbstractCodeDataProvider extension or implement AuthorizationCodeDataProvider directly
+    -->     
+    <bean id="oauthProvider" 
+          class="org.apache.cxf.fediz.service.oidc.OAuthDataProviderImpl"
+          init-method="init" destroy-method="close">
+        <!-- List of accepted scopes -->  
+        <property name="supportedScopes" ref="supportedScopes"/>
+        <!-- 
+             List of scopes that the consent/authorization form should make 
+             selected by default. For example, asking a user to do an extra click
+             to approve an "oidc" scope is a redundant operation because this scope
+             is required anyway.
+        -->
+        <property name="defaultScopes" ref="coreScopes"/>
+        
+        <property name="invisibleToClientScopes" ref="invisibleToClientScopes"/>
+        <!--
+        <property name="accessTokenLifetime" value="3600"/>
+        -->
+        <!--
+        <property name="supportPreauthorizedTokens" value="true"/>
+        -->
+        <property name="contextName" value="sts"/>
+    </bean>
+
+    <!-- Custom SubjectCreator where IdToken is created -->    
+    <bean id="subjectCreator" class="org.apache.cxf.fediz.service.oidc.FedizSubjectCreator">
+        <property name="idTokenIssuer" value="accounts.fediz.com"/>
+    </bean>
+         
+</beans>
+
diff --git a/systests/oidc/src/test/resources/sts.jaas b/systests/oidc/src/test/resources/sts.jaas
new file mode 100644
index 0000000..fdb759e
--- /dev/null
+++ b/systests/oidc/src/test/resources/sts.jaas
@@ -0,0 +1,10 @@
+
+sts {
+    org.apache.cxf.ws.security.trust.STSLoginModule required 
+    require.roles="true"
+    disable.on.behalf.of="true"
+    wsdl.location="https://localhost:${idp.https.port}/fediz-idp-sts/REALMA/STSServiceTransportUT?wsdl"
+    service.name="{http://docs.oasis-open.org/ws-sx/ws-trust/200512/}SecurityTokenService"
+    endpoint.name="{http://docs.oasis-open.org/ws-sx/ws-trust/200512/}TransportUT_Port";
+};
+