29-Apr-2020
03:35
- last edited on
21-Nov-2022
16:23
by
JimmyPackets
now I cannot login ltm via rest api , i thought the number of token of my account has reach the maximum .here is an error
login myhost fail b'{"code":401,"message":"remoteSender:http://localhost:8100/shared/authn/login, method:POST ","originalRequestBody":"{\\"username\\":\\"user\\",\\"loginProviderName\\":\\"tmos\\",\\"generation\\":0,\\"lastUpdateMicros\\":0}","referer":"ipaddress","restOperationId":124004534,"kind":":resterrorresponse"}'
here are my questions:
Solved! Go to Solution.
29-Apr-2020 19:57
It is not obvious from the error message you provided, however, a usual error message you get from authorization error (e.g., incorrect password) is "message": "Authentication failed." The issue may be a bit deeper than you may think. Try restarting the iControl REST framework daemon by running 'tmsh restart sys service restjavad'. If the issue still persists, I recommend you to file a service ticket to F5 support.
29-Apr-2020
06:31
- last edited on
21-Nov-2022
16:23
by
JimmyPackets
Hi, here is a routine I wrote for Ansible.
It´s validating an existing token before using it for the following tasks.
In case it is already invalid or it is expiring soon, a new token will be requested and stored for future use.
I use it i.e. for device onboarding, configuration and modification tasks.
Even if you don´t use Ansible it hopefully shows the REST calls applied.
It´s tested with TMOS v12-v15.
Cheers, Stephan
- name: request current token information
no_log: "{{ logging_disabled }}"
uri:
validate_certs: no
url: https://{{ inventory_hostname }}/mgmt/shared/authz/tokens/{{ device_info[inventory_hostname].token }}
method: GET
headers:
X-F5-Auth-Token: "{{ device_info[inventory_hostname].token }}"
status_code:
- 200
- 401
register: token_info
until: (token_info.status == 200) or
(token_info.status == 401)
retries: 90
delay: 10
when: (device_info is defined) and
(device_info[inventory_hostname] is defined) and
(device_info[inventory_hostname].token is defined)
- name: debug current token
debug:
msg:
- "auth status code: {{ token_info.status | default('undefined') }}"
- "token valid for: {{ (token_info.json.expirationMicros | int - token_info.json.lastUpdateMicros | int) // 1000000 }} seconds"
- "current token: {{ device_info[inventory_hostname].token | default('undefined') }}"
when: (device_info is defined) and
(device_info[inventory_hostname] is defined) and
(device_info[inventory_hostname].token is defined) and
(token_info.status != 401)
- name: aquire new token on error or if token would expire soon
no_log: "{{ logging_disabled }}"
uri:
validate_certs: no
url: https://{{ inventory_hostname }}/mgmt/shared/authn/login
method: POST
body_format: json
body:
username: admin
password: "{{ bigip_credentials_secure.admin }}"
loginProviderName: tmos
register: token_data
until: token_data.status == 200
retries: 60
delay: 10
when: (token_info.status is not defined) or
(token_info.status == 401) or
((token_info.status == 200) and (((token_info.json.expirationMicros | int - token_info.json.lastUpdateMicros | int) // 1000000) < 120))
- name: retrieve token from payload and store to data structure
set_fact:
device_info: "{{ device_info | default({}) | combine({inventory_hostname: {'token': token_data.json.token.token, 'expiration': token_data.json.token.expirationMicros}}, recursive=True) }}"
when: (token_data is defined) and
(token_data.status is defined) and
(token_data.status == 200)
- name: debug final token
debug:
msg:
- "final token: {{ device_info[inventory_hostname].token | default('undefined') }}"
when: (device_info is defined) and
(device_info[inventory_hostname] is defined) and
(device_info[inventory_hostname].token is defined)
...
29-Apr-2020
13:52
- last edited on
04-Jun-2023
21:29
by
JimmyPackets
1) The maximum number of tokens per user is set to 100 since BIG-IP 13.1. The response JSON body to a token request indicates: "user foo has reached maximum active login tokens" (seems like the response body you pasted does not contain this message, so you may be hitting some other issues).
2) To find the active tokens on the box, call a GET request to /mgmt/shared/authz/tokens. Use admin user.
3) The lifespan of token is 1200s (20 min) by default. You can change it by PATCHING the timeout property of the token: e.g. To change the lifetime of the token "AEDEM4TRWHGBET2TWOHM6ZBJKD" to 4200s;
curl -sk https://$HOST/mgmt/shared/authz/tokens/AEDEM4TRWHGBET2TWOHM6ZBJKD \
-X PATCH -H "Content-type: application/json" \
-H "X-F5-Auth-Token: AEDEM4TRWHGBET2TWOHM6ZBJKD" \
-d '{"timeout" : 4200}'
Note that the Authentication token is designed to be reused. If you are creating a token for each individual task, you may need to consolidate the tasks into one session and request just one token at the beginning of the session. If that's too tedious, you may want to make the timeout shorter.
4) You can delete the token by sending a DELETE method: e.g.,
curl -sku $PASS https://$HOST/mgmt/shared/authz/tokens/2PBX7ROP6H4GE6TQN4CUJVJYZG -X DELETE
Cheers
29-Apr-2020 18:39
thanks for you detail reply . look like login failure at my side is not caused by token limit , do you have any idea why login failure ,since I was able to login before . thanks
30-Apr-2020 00:52
Hi Satoshi San,
thanks for the answer and details. If I remember right I tested the ability to extend the tokens lifetime in the past and it didnt work as expected. I will check it again and reply in this thread.
I will add the deletion of the token to my Ansible tasks in case a token is about to expire.
(Especially in a device onboarding workflow a time of 20 minutes can be exceeded easily. That´s why I re-run the tasks above at critical points.)
As I´m re-using the token continuosly, there is little to no risk to exceed the per device limit. But for a clean deployment it makes sense to delete tokens in advance.
Thanks again & kind regards, Stephan
29-Apr-2020 19:57
It is not obvious from the error message you provided, however, a usual error message you get from authorization error (e.g., incorrect password) is "message": "Authentication failed." The issue may be a bit deeper than you may think. Try restarting the iControl REST framework daemon by running 'tmsh restart sys service restjavad'. If the issue still persists, I recommend you to file a service ticket to F5 support.
19-May-2020 20:53
thanks for your reply.
I have contact F5 support , it turn out the process on F5 , after restart javarestd , it recover
14-Nov-2022 12:02
Did they tell you what was the reason why you had to restart the service? I am asking you, because I am having a similar problem of 401 unauthorized when consulting via API, and it makes me think about token handling, because it is not something that happens all the time, but sometimes, but after seeing the problem that you had, I restarted the service and it started to work correctly. I'm running version BIG-IP
13-May-2020 13:37
09-May-2022 03:21
Perhaps you just want to remove the token right after running the API operation?
The script below is using an auth token to patch a sample configuration and afterwards the token will be deleted automatically:
# python script: apitest2.py
# version: 0.2 (2022--05-09)
# author: Stephan Manthey
# purpose:
# retrieve auth token
# modify configuration (enable/disable pool member) with token based auth
# delete auth token
# module requests required (installed via Python PIP):
# su -c 'yum install python-pip'
# su -c 'sudo pip2 install requests'
# su -c 'sudo pip3 install requests'
# or:
# su -c 'yum install python-requests'
# su -c 'yum install python3-requests'
import time
import json
import requests
from requests.packages.urllib3.exceptions import InsecureRequestWarning
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
username = 'username'
password = 'password'
bigipdev = '10.100.100.81'
poolname = 'pool_apitest'
nodename = '10.10.10.11'
nodeport = 80
authpath = 'https://{}/mgmt/shared/authn/login'.format(bigipdev)
conthead = {'Content-Type': 'application/json'}
authdata = {'username': username, 'password': password, 'loginProviderName': 'tmos'}
memberup = {'state': 'user-up', 'session': 'user-enabled'}
memberdown = {'state': 'user-down', 'session': 'user-disabled'}
session = requests.Session()
authtime = time.time()
tokenrequest = session.post(url=authpath,data=json.dumps(authdata),headers=conthead,verify=False)
print('got my token:','{:f}'.format(time.time() - authtime))
# print('token request:',tokenrequest.status_code)
if tokenrequest.status_code == 200:
tokendata = tokenrequest.json()
xauthhead = {'X-F5-Auth-Token': tokendata['token']['token'], 'Content-Type': 'application/json'}
querypath = 'https://{}/mgmt/tm/ltm/pool/~Common~{}/members/~Common~{}:{}'.format(bigipdev,poolname,nodename,nodeport)
print('patching now:','{:f}'.format(time.time() - authtime))
membermodify = session.patch(url=querypath,data=json.dumps(memberup),headers=xauthhead,verify=False)
print('1st response:','{:f}'.format(time.time() - authtime))
if membermodify.status_code == 200:
memberdata = membermodify.json()
membername = memberdata['name']
# print('member found:',membername)
else:
print('modification error:',membermodify.status_code)
exit()
membermodify = session.patch(url=querypath,data=json.dumps(memberdown),headers=xauthhead,verify=False)
print('2nd response:','{:f}'.format(time.time() - authtime))
if membermodify.status_code == 200:
memberdata = membermodify.json()
membername = memberdata['name']
# print('member found:',membername)
else:
print('modification error:',membermodify.status_code)
exit()
tokendelpath = 'https://{}/mgmt/shared/authz/tokens/{}'.format(bigipdev,tokendata['token']['token'])
tokendelete = session.delete(url=tokendelpath,headers=xauthhead,verify=False)
# print('token delete:', tokendelete.status_code)
if tokendelete.status_code != 200:
print('token delete error')
exit()
else:
print('error: no token provided')
exit()
PS: Probably you also want to add some lines to save into the startup configuration