Get hands-on experience with 20+ free Google Cloud products and $300 in free credit for new customers.

How to incorporate parameters into the Target Path?

I am trying to expose a Proxy API that requires mandatory parameters, and we want to isolate API consumers from that sort of implementation details when consuming our API.
The current API does not require an authentication method, it just requires passing the login/password as parameter in the body request + other mandatory parameters.

This is how we currently call the API (without Apigee) including the mandatory params:

Tana_Delg_4-1695941176872.png

 

Tana_Delg_5-1695941212964.png

To interact with the API in Apigee, consumers are expected to follow this pattern:

https://example.com/lawmas/v1/general-access-contracts
Where:
BasePath = /lawmas/v1
Target Path =/general-access-contracts

We require adding the mandatory parameters in target path, this is what I have so far:

1. I created two Key Values Maps for Encrypted Credentials (login, password) and Mandatory Parameters (KB,table, lan):

kvm.png

2. I added them in the Proxy Endpoint:

Tana_Delg_6-1695941335366.png

Tana_Delg_7-1695941352907.png

Tana_Delg_8-1695941386499.png

Proxy Endpoint > POST /general-access-contracts:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ProxyEndpoint name="default">
    <Description>LAWMAS - General Access Contracts</Description>
    <DefaultFaultRule name="default-fault">
        <Step>
            <Name>FC-ExceptionHandling</Name>
        </Step>
    </DefaultFaultRule>
    <PreFlow name="PreFlow">
        <Request/>
        <Response/>
    </PreFlow>
    <Flows>
        <Flow name="OptionsPreFlight">
            <Request/>
            <Response>
                <Step>
                    <Name>AM-Add_CORS</Name>
                </Step>
            </Response>
            <Condition>request.verb == "OPTIONS" AND request.header.origin != null AND request.header.Access-Control-Request-Method != null</Condition>
        </Flow>
        <Flow name="/general-access-contracts">
            <Condition>(proxy.pathsuffix MatchesPath "/general-access-contracts") and (request.verb = "POST")</Condition>
            <Description>List `General Access Contract` objects.</Description>
            <Request>
                <Step>
                    <Name>KVM-Get_Backend_Credentials</Name>
                </Step>
                <Step>
                    <Name>KVM-Get_TargetPathSufix</Name>
                </Step>
                <Step>
                    <Name>AM-Set_TargetPath_GeneralAccessContracts</Name>
                </Step>
            </Request>
            <Response/>
        </Flow>
        <Flow name="UnmatchedPaths">
            <Description/>
            <Request>
                <Step>
                    <Name>AM-404_Not_Found</Name>
                </Step>
                <Step>
                    <Name>RF-Custom_Errors</Name>
                </Step>
            </Request>
            <Response/>
            <Condition>(proxy.pathsuffix MatchesPath "**")</Condition>
        </Flow>
    </Flows>
    <PostFlow name="PostFlow">
        <Request/>
        <Response/>
    </PostFlow>
    <HTTPProxyConnection>
        <BasePath>/lawmas/v1</BasePath>
        <VirtualHost>https-external-apis</VirtualHost>
    </HTTPProxyConnection>
    <RouteRule name="NoRoute">
        <Condition>request.verb == "OPTIONS" AND request.header.origin != null AND request.header.Access-Control-Request-Method != null</Condition>
    </RouteRule>
    <RouteRule name="default">
        <TargetEndpoint>default</TargetEndpoint>
    </RouteRule>
</ProxyEndpoint>

However, it looks like the backend server is not accepting the parameters:

Tana_Delg_3-1695941092165.png

I would highly value any insights or information you could provide

Solved Solved
1 4 3,288
1 ACCEPTED SOLUTION

I think maybe you are using Apigee to "mediate security" on this API.  In other words, you want the Apigee API Proxy to check one set of credentials (maybe a token) and the upstream (backend?) system  should accept a different kind of credential.  Maybe it uses 2-way TLS, or something else.

If this i the case, then you may need to strip the credentials that you pass into Apigee, from the request that gets propagated to the target. 

From the error message "Wrong Authorization data", it. looks like the upstream is complaining about the authorization data, which is normally passed in an Authorization header. From the curl command you showed, which looks like it's the one that the Apigee Trace system will display for you, it appears there IS an Authorization header being propagated to the upstream system.   And also it looks like the OTHER request from Postman, the one that does not go through Apigee, passes no Authorization header at all.  And it succeeds. 

So what I suspect is that a valid request to the upstream must not include the access token which is known only by Apigee. 

To make this work, in the Apigee proxy you might call OAuthV2/VerifyAccessToken, and then immediately after that, use AssignMessage to remove the Authorization header. Configure the step like this: 

 

<AssignMessage name='AM-Remove-Authz-Header'>
  <Remove>
    <Headers>
      <Header name='Authorization'/>
    </Headers>
  </Remove>
</AssignMessage>

 

 But you may wish to have your approach reviewed by a security architect on your side. Passing the login and password on every request to the upstream is an anti-pattern.  Also, from the error message, the EWS system will accept and validate credentials passed in an Authorization header.  What I advised above is:

  1. Apigee proxy checks the inbound token (passed in the Authorization header)
  2. Apigee removes the inbound Authorization header
  3. Apigee sends login/password as query parameters in the request to upstream

Instead of that, a better approach might be :

  1. Apigee proxy checks the inbound token (passed in the Authorization header)
  2. Apigee removes that inbound Authorization header
  3. Apigee retrieves from a custom attribute on the apigee token, the token usable for the upstream
  4. Apigee injects that token into a NEW Authorization header. Apigee does not set login/password query params. The request to the upstream is simpler and more secure.

There are two kinds of token: one known by Apigee, and one known by the EWS upstream.  If you pass an Apigee token to the EWS upstream it will say "Wrong Authorization data".  But if you pass an EWS token to the EWS upstream, then it will probably work.

The trick is to figure out how to configure Apigee to get a token from the EWS upstream. Probably you'd do this with a ServiceCallout step, that calls https://ewsupstream.com/token or similar,  passing the login/password. Do this as a step during the Apigee token generation (right before OAuthV2/GenerateAccessToken).  Then attach the token returned by the EWS upstream, as a custom attribute on the apigee-generated token. 

 

View solution in original post

4 REPLIES 4
Top Solution Authors