Implemented a proxy url by using Basic Authentication and Key value pairs but unable to get the vlaues to the username and password

Configured username and password in the key value pairs

And get the user name and password by using the following policies

getUsername: this is used to get the username from the key value pairs.

<KeyValueMapOperations name="getUsername" mapIdentifier="BasicAuthCredentials">
  <DisplayName>getUsername</DisplayName>
  <Get assignTo="credentials.username" index="1">
   <Key>
    <Parameter ref="BasicAuth.credentials.username"/>
   </Key>
  </Get>
  <Scope>environment</Scope>
</KeyValueMapOperations>

getPassword:this is used to get the password from the key value pairs

<KeyValueMapOperationsname="getPassword" mapIdentifier="BasicAuthCredentials">
  <DisplayName>getPassword</DisplayName>
  <Get assignTo="credentials.password" index="1">
   <Key>
    <Parameter ref="BasicAuth.credentials.password"/>
   </Key>
  </Get>
  <Scope>environment</Scope>
</KeyValueMapOperations>

And my basic authentication policy is

<BasicAuthentication name="Basic-Authentication-1">
  <DisplayName>Basic Authentication-1</DisplayName>
  <Operation>Encode</Operation>
  <IgnoreUnresolvedVariables>false</IgnoreUnresolvedVariables>
  <User ref="BasicAuth.credentials.username"/>
  <!--<User ref="request.queryparam.username"/>-->
  <!--<Password ref="request.queryparam.password"/>-->
  <Password ref="BasicAuth.credentials.password"/>
  <AssignTo createNew="false">request.header.Authorization</AssignTo>
  <Source>request.header.Authorization</Source>
</BasicAuthentication>

I added header and base 64 encoded of username and password but unfortunately I am getting the following errors:

{"fault": {
"faultstring": "Unresolved variable : BasicAuth.credentials.username",
"detail": {"errorcode": "steps.basicauthentication.UnresolvedVariable"}
}}
Solved Solved
0 10 985
1 ACCEPTED SOLUTION

Hi, Rajesh

A couple tips here.

First, the documentation for the KeyValueMapOperations policy isn't very clear on this particular point, but I'll tell you: it is possible to use multiple Get elements in a single KeyValueMapOperations policy, if you are intending to retrieve multiple data items from the same map. For example, this is a working policy that I use to retrieve settings for Stackdriver.

<KeyValueMapOperations name='KVM-Get-Stackdriver-Settings' mapIdentifier='settings1'>
  <Scope>environment</Scope>
  <ExpiryTimeInSecs>30</ExpiryTimeInSecs>
  <!-- these gets will be cached -->
  <Get assignTo='stackdriver.projectid'>
    <Key>
      <Parameter>stackdriver.projectid</Parameter>
    </Key>
  </Get>
  <Get assignTo='stackdriver.logid'>
    <Key>
      <Parameter>stackdriver.logid</Parameter>
    </Key>
  </Get>
  <Get assignTo='stackdriver.jwt_issuer'>
    <Key>
      <Parameter>stackdriver.jwt_issuer</Parameter>
    </Key>
  </Get>
</KeyValueMapOperations>

That policy retrieves 3 items. In your case, using multiple Get elements in a single policy would also make sense. I'll make sure to get the documentation updated on this point.

#2. When you retrieve from the KVM, you specify a key. This may be obvious, but let me say it anyway because I'm pedantic: the KVM, as the name suggests, maps a key to a value. I can lookup "favorite-fruit" and get "apple". "favorite-fruit" is the key, and "apple" is the value.

In my case from the policy above, I was using "stackdriver.projectid" for the key for one of the data items. And the data returned will be "project-apigee-edge". This is a snap from the administrative UI For Apigee Edge, showing the contents of this KVM:

5402-screenshot-20170801-101202.png

In the policy configuration I used, the Get element looked like this:

  <Get assignTo='stackdriver.projectid'>
    <Key>
      <Parameter>stackdriver.projectid</Parameter>
    </Key>
  </Get>

That uses a fixed key "stackdriver.projectid" and maps it to a context variable (assignTo), with the same name. They need not be the same name, but I find it simpler to do it this way.

Now, in your configuration, the configuration looks like this:

 <Get assignTo="credentials.password" index="1">
   <Key>
    <Parameter ref="credentials.password"/>
   </Key>
 </Get>

What that says is ... the key itself is being retrieved from a context variable called "BasicAuth.credentials.password" . That's what the ref= attribute does; it says "get the value from this context variable." I think that's wrong. I think you don't want that. You don't want a variable key. I think maybe what you want is a fixed key, just in the same way that I am specifying a fixed key of "stackdriver.projectuid". I think you want something like this:

 <Get assignTo="credentials.password">
   <Key>
    <Parameter>credentials.password</Parameter>
   </Key>
 </Get>

Do you see the difference? No ref= attribute. The full policy with the 2 Get elements should be:

<KeyValueMapOperations name="getCredentials" mapIdentifier="BasicAuthCredentials">
  <DisplayName>getCredentials</DisplayName>
  <Get assignTo="credentials.username">
   <Key>
    <Parameter>credentials.username"</Parameter>
   </Key>
  </Get>
  <Get assignTo="credentials.password">
   <Key>
    <Parameter>credentials.password"</Parameter>
   </Key>
  </Get>
  <Scope>environment</Scope>
</KeyValueMapOperations>

#3. OK, once that policy executes, the context variable "credentials.password" and "credentials.username" will contain values. That means in your BasicAuthentication policy, you should refer to THOSE variables. Your policy referred to variables with the names BasicAuth.credentials.password, and BasicAuth.credentials.username, which I think is wrong. Also you used the Source element, which is sensible only when the Operation is Decode.

A better config might be:

<BasicAuthentication name="Basic-Authentication-1">
  <Operation>Encode</Operation>
  <IgnoreUnresolvedVariables>false</IgnoreUnresolvedVariables>
  <User ref="credentials.username"/>
  <Password ref="credentials.password"/>
  <AssignTo createNew="false">request.header.Authorization</AssignTo>
</BasicAuthentication>

Last thing: you should probably consider using an Encrypted KVM, if you are storing secrets there (like passwords).

View solution in original post

10 REPLIES 10

Hi, Rajesh

A couple tips here.

First, the documentation for the KeyValueMapOperations policy isn't very clear on this particular point, but I'll tell you: it is possible to use multiple Get elements in a single KeyValueMapOperations policy, if you are intending to retrieve multiple data items from the same map. For example, this is a working policy that I use to retrieve settings for Stackdriver.

<KeyValueMapOperations name='KVM-Get-Stackdriver-Settings' mapIdentifier='settings1'>
  <Scope>environment</Scope>
  <ExpiryTimeInSecs>30</ExpiryTimeInSecs>
  <!-- these gets will be cached -->
  <Get assignTo='stackdriver.projectid'>
    <Key>
      <Parameter>stackdriver.projectid</Parameter>
    </Key>
  </Get>
  <Get assignTo='stackdriver.logid'>
    <Key>
      <Parameter>stackdriver.logid</Parameter>
    </Key>
  </Get>
  <Get assignTo='stackdriver.jwt_issuer'>
    <Key>
      <Parameter>stackdriver.jwt_issuer</Parameter>
    </Key>
  </Get>
</KeyValueMapOperations>

That policy retrieves 3 items. In your case, using multiple Get elements in a single policy would also make sense. I'll make sure to get the documentation updated on this point.

#2. When you retrieve from the KVM, you specify a key. This may be obvious, but let me say it anyway because I'm pedantic: the KVM, as the name suggests, maps a key to a value. I can lookup "favorite-fruit" and get "apple". "favorite-fruit" is the key, and "apple" is the value.

In my case from the policy above, I was using "stackdriver.projectid" for the key for one of the data items. And the data returned will be "project-apigee-edge". This is a snap from the administrative UI For Apigee Edge, showing the contents of this KVM:

5402-screenshot-20170801-101202.png

In the policy configuration I used, the Get element looked like this:

  <Get assignTo='stackdriver.projectid'>
    <Key>
      <Parameter>stackdriver.projectid</Parameter>
    </Key>
  </Get>

That uses a fixed key "stackdriver.projectid" and maps it to a context variable (assignTo), with the same name. They need not be the same name, but I find it simpler to do it this way.

Now, in your configuration, the configuration looks like this:

 <Get assignTo="credentials.password" index="1">
   <Key>
    <Parameter ref="credentials.password"/>
   </Key>
 </Get>

What that says is ... the key itself is being retrieved from a context variable called "BasicAuth.credentials.password" . That's what the ref= attribute does; it says "get the value from this context variable." I think that's wrong. I think you don't want that. You don't want a variable key. I think maybe what you want is a fixed key, just in the same way that I am specifying a fixed key of "stackdriver.projectuid". I think you want something like this:

 <Get assignTo="credentials.password">
   <Key>
    <Parameter>credentials.password</Parameter>
   </Key>
 </Get>

Do you see the difference? No ref= attribute. The full policy with the 2 Get elements should be:

<KeyValueMapOperations name="getCredentials" mapIdentifier="BasicAuthCredentials">
  <DisplayName>getCredentials</DisplayName>
  <Get assignTo="credentials.username">
   <Key>
    <Parameter>credentials.username"</Parameter>
   </Key>
  </Get>
  <Get assignTo="credentials.password">
   <Key>
    <Parameter>credentials.password"</Parameter>
   </Key>
  </Get>
  <Scope>environment</Scope>
</KeyValueMapOperations>

#3. OK, once that policy executes, the context variable "credentials.password" and "credentials.username" will contain values. That means in your BasicAuthentication policy, you should refer to THOSE variables. Your policy referred to variables with the names BasicAuth.credentials.password, and BasicAuth.credentials.username, which I think is wrong. Also you used the Source element, which is sensible only when the Operation is Decode.

A better config might be:

<BasicAuthentication name="Basic-Authentication-1">
  <Operation>Encode</Operation>
  <IgnoreUnresolvedVariables>false</IgnoreUnresolvedVariables>
  <User ref="credentials.username"/>
  <Password ref="credentials.password"/>
  <AssignTo createNew="false">request.header.Authorization</AssignTo>
</BasicAuthentication>

Last thing: you should probably consider using an Encrypted KVM, if you are storing secrets there (like passwords).

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<KeyValueMapOperations async="false" continueOnError="false" enabled="true" name="getUsername" mapIdentifier="BasicAuthCredentials">
<DisplayName>getUsername</DisplayName>
<Properties/>

<Get assignTo="credentials.username">
<Key>
<!--<Parameter ref="credentials.username"/>-->
<Parameter>credentials.username</Parameter>
</Key>
</Get>
<Get assignTo="credentials.password">
<Key>
<Parameter>credentials.password</Parameter>
</Key>
</Get>
<Scope>environment</Scope>
</KeyValueMapOperations>

But throwing the same error and modifed in basic authentication also like below

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<BasicAuthentication async="false" continueOnError="false" enabled="true" name="Basic-Authentication-1">
<DisplayName>Basic Authentication-1</DisplayName>
<Operation>Encode</Operation>
<IgnoreUnresolvedVariables>false</IgnoreUnresolvedVariables>
<User ref="credentials.username"/>
<!--<User ref="request.queryparam.username"/>-->
<!--<Password ref="request.queryparam.password"/>-->
<Password ref="credentials.password"/>
<AssignTo createNew="false">request.header.Authorization</AssignTo>
<Source>request.header.Authorization</Source>
</BasicAuthentication>

yes - and have you verified that the KVM has those KEYS and the correct VALUES ?

post a screenshot?

yes i verified

Below is the screen shot

In that case, I suggest using the Apigee Trace UI to diagnose this further. You will want to verify that the KVM Get is setting the variables as expected.

Also, you are not using the configuration I suggested o the BasicAuthentication policy. Just sayin. Maybe you want to re-check my advice. (Don't use Source element)

Hello Dino,

I got successful result.I made one mistakes that is I configured key and value pairs at

environment level. At the time of getting those values in kvm policies the key name is

different then what is mentioned in environment level so that I got "unresolved error"

In the policy i given name as "credentials.username" instead the exact name(user name)

what I configured. In the documentation it has some ambiguities with the statements what

they mentioned in policies of Basic authentication(outbound) it is better to specify more clear.

below is my modified KVM policy.

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<KeyValueMapOperations async="false" continueOnError="false" enabled="true" name="getUsername" mapIdentifier="BasicAuthCredentials">
<DisplayName>getUsername</DisplayName>
<Properties/>
<Get assignTo="credentials.username">
<Key>
<!--<Parameter ref="credentials.username"/>-->
<Parameter>username</Parameter>
</Key>

</Get>
<Get assignTo="credentials.password">
<Key>
<Parameter>password</Parameter>
</Key>
</Get>
<Scope>environment</Scope>
</KeyValueMapOperations>

Hi Rajesh. I'm so glad you were able to resolve your problem!

Please give me more information about the ambiguities - we would like our documentation to be as clear and helpful as possible. If you have specific suggestions on how to make things clearer, or even specific examples of what you found to be unclear, I would like to know.

also I'll flag this for @Stephen Gilson .

Dear Dino,

I followed basic authentication policy in the document there initially we have outbound processing.I configured my policy according to the information available. In that it is necessary to provide more detailed information like whats the process to retrieving key and values from the map.There you given "credentials.username" and "BasicAuth.credentials.username" at <assign to> and <Parameter> tag so could you please provide some additional information about these two tags and also provide some detailed information about this below example what you mentioned in the documentation

-->For getting user name
<KeyValueMapOperationsname="getUsername"mapIdentifier="BasicAuthCredentials">
<Scope>apiproxy</Scope>
<GetassignTo="credentials.username"index='1'>
<Key><Parameterref="BasicAuth.credentials.username"/>
</Key>
</Get>
</KeyValueMapOperations


-->For getting password

<KeyValueMapOperations name="getPassword" mapIdentifier="BasicAuthCredentials">
   <Scope>apiproxy</Scope>
   <Get assignTo="credentials.password" index='1'>
      <Key>
         <Parameter ref="BasicAuth.credentials.password"/> 
      </Key>
   </Get>
</KeyValueMapOperations>



They given values in wrong order for both <Get assignTo> and <key>
I think,

<Get assignTo="BasicAuth.credentials.password"/>
<Key>
<Parameter ref="credentials.password"/>
</Key>
</Get>


And Dino,The most important thing is could you please provide
 information about the location where we create the key and value
 pairs (about environment configuration).