Wiki source code of Android Authenticator

Last modified by Vincent Massol on 2024/02/26 17:53

Show last authors
1 This page presents the design, architecture and general technical/implementation details of the [[Android Authenticator>>extensions:Extension.Android authenticator]] project.
2
3 The idea of this project is to integrate a wiki instance in Android accounts, mainly including the synchronization of contacts and the XWiki authenticator. By synchronizing contacts of your company on your phone, it's easy to communicate and collaborate with each other. And the authenticator can also be used to provide credentials for other android apps.
4
5 There're mainly the following key tasks, such as
6
7 - restful/solr http connector
8 - authenticator service
9 - synchronization service
10 - large capacity performance
11 - security issues
12
13
14 [[image:design.jpg]]
15
16
17
18 (((
19 First introduce the design and implementation of the synchronization and authenticator
20 )))
21
22 = **Synchronization** =
23
24 == Server->Client Sync ==
25
26 There are two choices, including synchronizing all users or synchronizing the users of selected groups. We use the same method for these two cases.
27
28 === Add Update ===
29
30 Each time while periodecally calling the synchronization method SyncAdapter.onPerformSync, we get data from server that has been modified since the last modified time. The data that we get must be updated or add to the local contact2 database. Also only these data need to be updated.
31
32 === Delete ===
33
34 What data should be deleted for the local database? Because the server does not return data that needs to be deleted, or maybe I do not know how to query the deleted objects? Therefor now I just get all the user IDs(HashSet<ids>), traverse every user of the local database, find the users that are not contained in the HashSet, and these data need to be deleted, and then delete them.
35
36 === Detail ===
37
38 For synchronizing all users:
39
40 1) Get all users as List<SearchResult> searchResults
41
42 2) Add Update: SearchResults include the last modified time. So according to the time, we can filter what data should be updated or added. Then call the function ContactManager.UpdateContacts to update local db.
43
44 3) Delete: searchResults already have user ids, so we can get the IDs(HashMap<id,Ojbect>), then traverse the local database to find what data should be deleted.
45
46 For synchronizing users of selected groups:
47
48 1) Get all selected group ids from local sharepreference xml, as List<String> groupIds
49
50 2) Get the users' simple information(ObjectSummary) of each group one by one. The ObjectSummary only has the user's id without the last modified time.
51
52 3) Add Update: According to the user ids, we get the last modified time for each user, if before the given last sync time, continue; if after, we update user (but we need first get the detailed information of the user.).
53
54 4) Delete: at seconde step, we get ObjectSummarys which include all the user ids. So with these ids, we can find the data that should be deleted.
55
56 === Code Detail ===
57
58 SyncAdapter.onPerformSync()
59 1 XWiki.getUserList. get all users that have been modified after lastmodifiedtime from server.
60 2 ContactManager.UpdateContacts. (add update delete the local database)
61 2.1 add users if lookupRawContact return false;
62 2.2 update users if lookupRawContact return true;
63 2.3 delete users
64 2.3.1 XWikiHttp.getAllUserMap from server as A.
65 2.3.2 getAllContactsIdMap from local database as B.
66 2.3.3 delete the user [B-A] that is in B but not in A.\\
67
68 == Client->Server Sync ==
69
70 For this part, As we will first update the server while editing the contact, Therefore, unnecessary synchronization mechanism is not required. If the server's response is that the editor has no permission, we return; if has been updated in the server, we will update the local database at the same time.
71
72 EditContactActivity.updateContact()
73 1 check if input values if valid
74 2 Request to update contact in server
75 2.1 If having no permission, give up.
76 2.2 If having permission, update local database
77 3 NOTE: Update server first, if the response is ok, then update local database.
78
79
80 = **Authenticator** =
81
82 ~1. How to grant the permission for third party apps when they calling getAuthToken? (Here, AuthToken is equal to Cookie.JessionId)
83
84 Basically, only 3 useful interfaces, like AddNewAccount, getAuthToken, invalideAuthToken, are available for other third party android apps. The most widely used is getAuthToken. How should we grant permission for third-party apps? And when we grant? If adding XWiki account from one app, then we can trust this app and grant the getAuthToken permission. But if not, we should check the permission for every getAuthToken request of third-party apps. So the checking logic code should be in the function getAuthToken. But XWikiAuthenticator.getAuthToken will never be called if AcountManager has cached the authtoken corresponding to AuthTokenType. Therefore for first granting permission for third-party apps, the app should not pass the same authTokenType when calling getAuthToken function. Or the authToken value will be directly returned by AcountManager according to the same AuthTokenType and the method getAuthToken will never be called. So different apps should use the different AuthTokenType param to call the function getAuthToken so that the <AuthTokenType, AuthToken> will not be cached before granting permission for this app. AuthTokenType=FULL_ACCESS+PackageName. So in XWikiAuthenticator.getAuthToken function, if we check that the third-party app has not been granted, we startActivity(GrantPermissionAcvivity) to grant permission for this package by checking the user's input password.
85 And in addition the packageName can't be forged because we can use the options.getInt(AccountManager.KEY_CALLER_UID) to verify the pakageName.
86
87
88 2. How to maintain authToken consistency for different third-party apps with different AuthTokenType?
89
90 When will appear inconsistent? There are mainly two key cases, the authToken is expired or the third-party app calls the invalideAuthToken function. Now, I use the following solution to these problems.
91 1) When the authToken is expired, xwiki authenticator app will login again and refresh all the cached authToken for every AuthTokenType.
92 2) When the third-party app calls the invalidAuthToken function, then corresponding cache will be clear and getAuthToken will be called, then XWikiHttp.login will be called to get a new token and refresh all the cached authToken for every AuthTokenType.
93 3) So if any one finds the authToken has been expired, then login and refresh all the cached authToken to maintain consistency. In addition, I suggest that if the third-party app find the authToken is expired after a period of time, then first call getAuthToken again. If the token is different, then maybe authenticator has already update the token. If the token is the same, just call invalidAuthToken and getAuthToken again.
94
95 == Process ==
96
97 ~1. ask for Permission Granting. If permission granted, store in preference.
98 2. after passing 1 step, peekAuthToken to get an cached token for different AuthTokenType(FULL_ACESS+PackageName). If get a token that is not null, return.
99 3. if step 2 fails, ask XWiki-server for a new token. If failed return network error.
100
101 == Main classes and functions ==
102
103 Authenticator
104 AuthenticatorActivity
105 XWikiAuthenticator
106 getAuthToken()
107 invalideAuthToken
108 addNewAccount
109 XWikiAuthenticatorService
110 AccountManager
111 AccountManagerService\\
112
113 Note: for third-party apps, there are mainly the following apis:
114
115 ~1. getAuthToken
116 2. invalideAuthToken
117 Generally, only when we find the authToken getting from getAuthToken function was expired, we will invalide the token and let go to authenticator.getAuthToken
118 3. addNewContact
119 4. confirmCredentials
120
121
122
123 = **Rest Api and Solr Query **about users and groups =
124
125
126 *Sign In
127
128 [[http:~~/~~/localhost:8080/xwiki/bin/login/XWiki/XWikiLogin>>url:http://localhost:8080/xwiki/bin/login/XWiki/XWikiLogin]]
129
130 [[http:~~/~~/www.xwiki.org/xwiki/bin/login/XWiki/XWikiLogin>>url:http://www.xwiki.org/xwiki/bin/login/XWiki/XWikiLogin]]
131
132 user:passwd
133
134 dXNlcjpwYXNzd2Q=
135
136 curl -u user:passwd http:~/~/localhost:8080/xwiki/bin/login/XWiki/XWikiLogin -v
137
138 curl -X GET -H "Content-type: application/x-www-form-urlencoded" -H "Authorization: Basic dXNlcjpwYXNzd2Q=" http:~/~/localhost:8080/xwiki/bin/login/XWiki/XWikiLogin -v
139
140 curl -X GET -H "Content-type: application/x-www-form-urlencoded" -H " Cookie: JSESSIONID=v2ozvkq8meij34sblzcss1j;Path=/xwiki" http:~/~/localhost:8080/xwiki/bin/login/XWiki/XWikiLogin -v
141
142
143 *Sign Up
144
145 [[http:~~/~~/127.0.0.1:8080/xwiki/bin/view/XWiki/Registration>>url:http://127.0.0.1:8080/xwiki/bin/view/XWiki/Registration]]
146
147 [[http:~~/~~/www.xwiki.org/xwiki/bin/view/XWiki/RealRegistration>>doc:xwiki:XWiki.RealRegistration]]
148
149 curl -u username:passwd –X POST –H "Content-type: application/x-www-form-urlencoded" –d "form_token=" –d "parent=xwiki:Main.UserDirectory" –d "register_first_name=" –d "register_last_name" –d "xwikiname" –d "register_password" –d "register2_password" –d "register_email" –d "captcha_answer" –d "template=XWiki.XWikiUserTemplate" –d "xredirect=/xwiki/bin/view/Main/UserDirectory" [[http:~~/~~/127.0.0.1:8080/xwiki/bin/view/XWiki/Registration>>url:http://210.76.192.253:8080/xwiki/bin/view/XWiki/Registration]] -v
150
151 return all 200ok, so I use jsoup to analyze the returned html. If it contains the login button, I think it’s successful for this registeration.
152
153
154 ~* Get All Users:
155
156 default number<=10
157 [[http:~~/~~/www.xwiki.org/xwiki/rest/wikis/query?q=object:XWiki.XWikiUsers>>doc:xwiki:rest.wikis.query||queryString="q=object:XWiki.XWikiUsers"]]
158 [[http:~~/~~/www.xwiki.org/xwiki/rest/wikis/query?q=object:XWiki.XWikiUsers&number=100>>doc:xwiki:rest.wikis.query||queryString="q=object:XWiki.XWikiUsers&number=100"]]
159
160
161 ~* Get User Information(DONE)
162 for example XWiki.LudovicDubost
163 [[http:~~/~~/www.xwiki.org/xwiki/rest/wikis/xwiki/spaces/XWiki/pages/LudovicDubost>>doc:xwiki:rest.wikis.xwiki.spaces.XWiki.pages.LudovicDubost]]
164 {{id name="OLE_LINK2"/}}{{id name="OLE_LINK1"/}}[[http:~~/~~/www.xwiki.org/xwiki/rest/wikis/xwiki/spaces/XWiki/pages/LudovicDubost/objects/XWiki.XWikiUsers/0/properties>>doc:xwiki:rest.wikis.xwiki.spaces.XWiki.pages.LudovicDubost.objects.XWiki\.XWikiUsers.0.properties]]
165
166
167 ~* Get user’s Avatar
168
169 For example:
170
171 [[http:~~/~~/www.xwiki.org/xwiki/bin/view/XWiki/LudovicDubost>>doc:xwiki:XWiki.LudovicDubost]]
172
173 Get avatar image name (ludo3.jpg):
174
175 [[http:~~/~~/www.xwiki.org/xwiki/rest/wikis/xwiki/spaces/XWiki/pages/LudovicDubost/objects/XWiki.XWikiUsers/0/properties>>doc:xwiki:rest.wikis.xwiki.spaces.XWiki.pages.LudovicDubost.objects.XWiki\.XWikiUsers.0.properties]]
176
177 Get the image attachment:
178
179 [[http:~~/~~/www.xwiki.org/xwiki/bin/download/XWiki/LudovicDubost/ludo3.jpg>>attach:xwiki:[email protected]]]
180
181
182 *Get User’s last modified time:
183
184 [[http:~~/~~/www.xwiki.org/xwiki/rest/wikis/xwiki/spaces/XWiki/pages/zhouwenhai>>doc:xwiki:rest.wikis.xwiki.spaces.XWiki.pages.zhouwenhai]]
185
186 <modified>2014-07-28T03:04:44+02:00</modified>
187
188 [[http:~~/~~/www.xwiki.org/xwiki/rest/wikis/query?q=object:XWiki.XWikiUsers%20and%20name:fitz>>doc:xwiki:rest.wikis.query||queryString="q=object:XWiki.XWikiUsers and name:fitz"]]
189
190 <searchResult>
191
192 <modified>2016-04-19T10:52:26+02:00</modified>
193
194 </searchResult>
195
196
197 ~* Get Groups(DONE)
198 [[http:~~/~~/www.xwiki.org/xwiki/rest/wikis/query?q=wiki:xwiki%20and%20object:XWiki.XWikiGroups&number=20>>doc:xwiki:rest.wikis.query||queryString="q=wiki:xwiki and object:XWiki.XWikiGroups&number=20"]]
199
200 \\
201
202 ~* Get User From Group(DONE)
203 for example XWikiAdminGroup:
204 [[http:~~/~~/www.xwiki.org/xwiki/rest/wikis/xwiki/spaces/XWiki/pages/XWikiAdminGroup>>doc:xwiki:rest.wikis.xwiki.spaces.XWiki.pages.XWikiAdminGroup]]
205 [[http:~~/~~/www.xwiki.org/xwiki/rest/wikis/xwiki/spaces/XWiki/pages/XWikiAdminGroup/objects/XWiki.XWikiGroups>>doc:xwiki:rest.wikis.xwiki.spaces.XWiki.pages.XWikiAdminGroup.objects.XWiki\.XWikiGroups]]
206
207
208 ~* Edit Contact
209 curl -u username:passwd -X PUT -H "Content-type: application/x-www-form-urlencoded" -H "Accept: application/xml" -d "className=XWiki.XWikiUsers" -d "property#company=iie" http:~/~/localhost:8080/xwiki/rest/wikis/xwiki/spaces/XWiki/pages/username/objects/XWiki.XWikiUsers/0
210 curl -u username:passwd -X PUT -H "Content-type: application/x-www-form-urlencoded" -d "className=XWiki.XWikiUsers" -d "property#company=iiedacas" http:~/~/localhost:8080/xwiki/rest/wikis/xwiki/spaces/XWiki/pages/username/objects/XWiki.XWikiUsers/0
211
212 ~* Edit Test Object
213 $ curl -u Admin:admin
214 -X POST -H "Content-type: application/x-www-form-urlencoded"
215 -H "Accept: application/xml"
216 -d "className=XWiki.TestClass"
217 -d "property#test=Whatever you want"
218 http:~/~/localhost/xwiki/rest/wikis/xwiki/spaces/Test/pages/Test/objects
219
220
221 ~* Create a new page
222 create page
223 curl -u Admin:admin -X PUT ~-~-data-binary "@newpage.xml" -H "Content-Type: application/xml" http:~/~/localhost:8080/xwiki/rest/wikis/xwiki/spaces/Main/pages/NewPage
224 newpage.xml:
225 <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
226 <page xmlns="http:~/~/www.xwiki.org">
227 <title>Hello world</title>
228 <syntax>xwiki/2.0</syntax>
229 <content>This is a new page</content>
230 </page>
231
232 ~* Delete
233 curl -v -u Admin:admin
234 -X DELETE http:~/~/localhost:8080/xwiki/rest/wikis/xwiki/spaces/Main/pages/WebHome
235
236
237 \\

Get Connected