<?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:jaxrs="http://cxf.apache.org/jaxrs"
      xmlns:jaxrsclient="http://cxf.apache.org/jaxrs-client"
      xsi:schemaLocation="
         http://www.springframework.org/schema/beans 
         http://www.springframework.org/schema/beans/spring-beans.xsd
         http://cxf.apache.org/jaxrs
         http://cxf.apache.org/schemas/jaxrs.xsd
         http://cxf.apache.org/jaxrs-client
         http://cxf.apache.org/schemas/jaxrs-client.xsd">

     <!-- CXF Logging Feature -->
     <bean id="loggingFeature" class="org.apache.cxf.ext.logging.LoggingFeature"/>

     <!-- 
        1. Big Query Client Application: 
        accepts a form query and uses an OAuth2 access token to query BigQuery service
        with a bigQueryClient client  
     -->
     <jaxrs:server id="bigQueryServer" address="/search">
        <jaxrs:serviceBeans>
           <ref bean="bigQueryService"/>
        </jaxrs:serviceBeans>
        <jaxrs:providers>
           <!-- Checks that a client is authenticated with Google -->
           <ref bean="oidcRpFilter"/>
           
           <!-- supports the mapping of the big query search result to HTML --> 
           <ref bean="searchView"/>
           
           <!-- JAX-RS provider that makes OidcClientTokenContext available as JAX-RS @Context -->
           <ref bean="clientTokenContextProvider"/>
        </jaxrs:providers>
        <jaxrs:features>
           <ref bean="loggingFeature"/>
        </jaxrs:features>
     </jaxrs:server> 
     
     <!-- JAX-RS provider that makes OidcClientTokenContext available as JAX-RS @Context -->
     <bean id="clientTokenContextProvider" class="org.apache.cxf.rs.security.oauth2.client.ClientTokenContextProvider"/>
     
     <bean id="bigQueryService" class="demo.jaxrs.server.BigQueryService">
         <property name="bigQueryClient" ref="bigQueryClient"/>
     </bean>

     <!-- project_id is allocated in Google Developer Console -->
     <jaxrsclient:client id="bigQueryClient" threadSafe="true" 
        address="https://www.googleapis.com/bigquery/v2/projects/${project_id}/queries"
        serviceClass="org.apache.cxf.jaxrs.client.WebClient">
        <jaxrsclient:headers>
            <entry key="Accept" value="application/json"/>
            <entry key="Content-Type" value="application/json"/>
        </jaxrsclient:headers>
        <jaxrsclient:providers>
           <bean class="org.apache.cxf.jaxrs.provider.json.JsonMapObjectProvider"/>
        </jaxrsclient:providers>
     </jaxrsclient:client>
     
     <bean id="searchView" class="org.apache.cxf.jaxrs.provider.RequestDispatcherProvider">
         <property name="useClassNames" value="true"/>
         <property name="locationPrefix" value="/forms/"/>
         <property name="beanName" value="data"/>
     </bean>
     
     <bean id="oidcRpFilter" class="org.apache.cxf.rs.security.oidc.rp.OidcRpAuthenticationFilter">
         <!-- 
              This state manager is shared between this filter and the RP endpoint, 
              the RP endpoint sets an OIDC context on it and this filter checks the context is available 
         -->
         <property name="clientTokenContextManager" ref="stateManager"/>
         
         <!-- The address to redirect to if no OIDC context is available -->
         <property name="redirectUri" value="/forms/simpleLogin.jsp"/>    
     </bean>
     
     <!-- 
        2. OIDC RP endpoint: authenticates a user by redirecting a user to Google, and redirects the user 
                             to the initial application form once the authentication is done
     -->                        
     <jaxrs:server id="oidcRpServer" address="/oidc">
        <jaxrs:serviceBeans>
           <ref bean="oidcRpService"/>
        </jaxrs:serviceBeans>
        <jaxrs:providers>
           <!-- the filter which does the actual work for obtaining an OIDC context -->
           <ref bean="rpOidcRequestFilter"/>
           
           <!-- JAX-RS provider that makes OidcClientTokenContext available as JAX-RS @Context -->
           <ref bean="clientTokenContextProvider"/>
        </jaxrs:providers>
        <jaxrs:features>
           <ref bean="loggingFeature"/>
        </jaxrs:features>
     </jaxrs:server>
     
     <bean id="oidcRpService" class="org.apache.cxf.rs.security.oidc.rp.OidcRpAuthenticationService">
         <!-- This state manager is shared between this RP endpoint and the oidcRpFilter which protects
              the application endpoint, the RP endpoint sets an OIDC context on it and the filter checks 
              the context is available -->
         <property name="clientTokenContextManager" ref="stateManager"/>
         <!-- Where to redirect to once the authentication is complete -->
         <property name="defaultLocation" value="/service/search/start"/>
     </bean>
     <!-- The state manager shared between the RP and application endpoints -->
     <bean id="stateManager" class="org.apache.cxf.rs.security.oauth2.client.MemoryClientTokenContextManager"/>
     
     <!-- This filter redirect to Google Authorization service, exchanges an authorization code for access token,
          extracts OIDC IdToken, requests OIDC UserInfo and makes it all available as OidcCientTokenContext
     -->
     <bean id="rpOidcRequestFilter" class="org.apache.cxf.rs.security.oidc.rp.OidcClientCodeRequestFilter">
         <property name="clientCodeStateManager" ref="rpClientCodeStateManager"/>
         <property name="scopes" value="openid email profile https://www.googleapis.com/auth/bigquery.readonly"/>
         <property name="accessTokenServiceClient" ref="atServiceClient"/>
         <property name="idTokenReader" ref="idTokenReader"/>
         <property name="userInfoClient" ref="userInfoClient"/>
         <property name="consumer" ref="consumer"/>
         <property name="authorizationServiceUri" value="https://accounts.google.com/o/oauth2/auth"/>
         <property name="startUri" value="rp"/>
         <property name="completeUri" value="rp/complete"/>
     </bean>
     <!-- This state manager creates an OAuth2 'state' parameter and saves it in the HTTP session -->
     <bean id="rpClientCodeStateManager" class="org.apache.cxf.rs.security.oauth2.client.MemoryClientCodeStateManager"/>
     
     <!-- WebClient for requesting an OAuth2 Access token.
          rpOidcRequestFilter uses it to exchange a code for a token --> 
     
     <jaxrsclient:client id="atServiceClient" threadSafe="true" 
        address="https://accounts.google.com/o/oauth2/token"
        serviceClass="org.apache.cxf.jaxrs.client.WebClient">
        <jaxrsclient:headers>
            <entry key="Accept" value="application/json"/>
        </jaxrsclient:headers>
        <jaxrsclient:providers>
           <bean class="org.apache.cxf.jaxrs.provider.FormEncodingProvider">
               <property name="expectedEncoded" value="true"/>
           </bean> 
        </jaxrsclient:providers>
        <jaxrsclient:features>
           <ref bean="loggingFeature"/>
        </jaxrsclient:features>
     </jaxrsclient:client> 
     
     <bean id="idTokenReader" class="org.apache.cxf.rs.security.oidc.rp.IdTokenReader">
         <property name="jwkSetClient" ref="jwkSetClient"/> 
         <property name="issuerId" value="accounts.google.com"/>
         <property name="clockOffset" value="10"/>
     </bean>
     <bean id="userInfoClient" class="org.apache.cxf.rs.security.oidc.rp.UserInfoClient">
         <property name="userInfoServiceClient" ref="userInfoServiceClient"/>
     </bean>
     
     <!-- WebClient for requesting an OIDC IDP JWK Set 
          This client is used to get a JWK key required to validate OIDC IdToken returned with the OAuth2 access token -->
     <jaxrsclient:client id="jwkSetClient" threadSafe="true" 
        address="https://www.googleapis.com/oauth2/v2/certs"
        serviceClass="org.apache.cxf.jaxrs.client.WebClient">
        <jaxrsclient:headers>
            <entry key="Accept" value="application/json"/>
        </jaxrsclient:headers>
        <jaxrsclient:providers>
           <bean class="org.apache.cxf.rs.security.jose.jaxrs.JsonWebKeysProvider"/> 
        </jaxrsclient:providers>
        <jaxrsclient:features>
           <ref bean="loggingFeature"/>
        </jaxrsclient:features>
     </jaxrsclient:client>
     
     <!-- WebClient for requesting an OIDC UserInfo  
     This client is optional if the application is happy working with OIDC IDToken only -->
     
     <jaxrsclient:client id="userInfoServiceClient" threadSafe="true" 
        address="https://openidconnect.googleapis.com/v1/userinfo"
        serviceClass="org.apache.cxf.jaxrs.client.WebClient">
        <jaxrsclient:headers>
            <entry key="Accept" value="application/json"/>
        </jaxrsclient:headers>
        <jaxrsclient:providers>
           <bean class="org.apache.cxf.jaxrs.provider.json.JsonMapObjectProvider"/> 
        </jaxrsclient:providers>
        <jaxrsclient:features>
           <ref bean="loggingFeature"/>
        </jaxrsclient:features>
     </jaxrsclient:client>
     
     <!-- Client id and secret allocated in Google Developer Console -->
     <bean id="consumer" class="org.apache.cxf.rs.security.oauth2.client.Consumer">
         <property name="clientId" value="${client_id}"/> 
         <property name="clientSecret" value="${client_secret}"/>
     </bean>     
</beans>

