-
Notifications
You must be signed in to change notification settings - Fork 783
Conversation
Thanks for this contribution. Just a first comment: We already have an |
Ok, I just noticed that this only works for the api part, but not for the internal implementation as this would introduce a dependency from smarthome.core to Jetty bundles, which we probably do not want. |
FTR: I have moved the implementation to a new bundle |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Haven't found any time to look at the code itself.
Just a short question: Shouldn't new contributions use annotations instead of OSGI-INF/*.xml files?
@maggu2810 At code level I am using annotations. Happy to follow if anyone can confirm to remove OSGI-INF/*.xml please? |
@garytse Certainly so, see A.10 of our coding guidelines. |
* @author Gary Tse - Initial contribution | ||
* | ||
*/ | ||
@Component(name = "org.eclipse.smarthome.auth.oauth2.client.OAuthClientService", servicefactory = true, property = { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
configurationPid="org.eclipse.smarthome.any.pid", configurationPolicy=REQUIRE
would enable the creation of multiple instances of OAuthClientServiceImpl
.
If we do this, and if the component has a configuration policy of required
as shown above, then we will get multiple instances of the component, with each instance potentially receiving different configuration data. DS will continue to maintain all the service references in our component of course.
* | ||
*/ | ||
@Component(name = "org.eclipse.smarthome.auth.oauth2.client.OAuthClientService", servicefactory = true, property = { | ||
"tokenExpiresInBuffer=60" }) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can also extract this as an externalized configuration through config admin and you can introduce a metatype XML descriptor for that as well.
* | ||
* It is only valid for one-time-only to get the access token. | ||
* | ||
* https://tools.ietf.org/html/rfc6749#section-4 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
* Redirect URI. This is read by the authorization server. The URI should be | ||
* somewhere in the client application ready to receive the tokens. | ||
* | ||
* {@see https://tools.ietf.org/html/rfc6749#section-3.1.2} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
without brackets
* | ||
* If left null, a random state will be generated. | ||
* | ||
* {@see https://tools.ietf.org/html/rfc6749#section-5.2} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
without brackets
* {@link https://tools.ietf.org/html/rfc6749#section-1.4} | ||
* | ||
* This token must be confidential in transit and storage. | ||
* https://tools.ietf.org/html/rfc6749#section-10.3 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
|
||
/** | ||
* Token type. e.g. Bearer, MAC | ||
* {@see https://tools.ietf.org/html/rfc6749#section-7.1} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
without curly braces
|
||
/** | ||
* Number of seconds that this OAuthToken is valid for since the time it was created. | ||
* {@link https://tools.ietf.org/html/rfc6749#section-4.2.2} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
* the client by the resource owner. Unlike access tokens, refresh tokens are | ||
* intended for use only with authorization servers and are never sent | ||
* to resource servers. | ||
* {@link https://tools.ietf.org/html/rfc6749#section-1.5} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@see without braces
* {@link https://tools.ietf.org/html/rfc6749#section-1.5} | ||
* | ||
* This token must be confidential in transit and storage. | ||
* {@link https://tools.ietf.org/html/rfc6749#section-10.4} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@see without braces
* by the authorization server to inform the client of the scope of the access token | ||
* issued. | ||
* | ||
* {@link https://tools.ietf.org/html/rfc6749#section-3.3} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@see without braces
* If the "state" parameter was present in the client authorization request. | ||
* The exact value received from the client. | ||
* | ||
* {@link https://tools.ietf.org/html/rfc6749#section-4.2.2} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@see without braces
* then this call can be used to get a new acess token by using the refresh token. | ||
* | ||
* @param oauthProviderParams | ||
* @param lastOAuthToken refresh token in lastOAuthToken *MUST* be available (not null). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can make MUST bold. <b>MUST</b>
* @param lastOAuthToken refresh token in lastOAuthToken *MUST* be available (not null). | ||
* @return new OAuthToken from authorization server. The new token will be saved in store with encryption. | ||
* @throws IOException Web/ network issues etc. | ||
* @throws OAuthError For OAUTH error responses. {@see https://tools.ietf.org/html/rfc6749#section-5.2} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
no braces
/** | ||
* | ||
*/ | ||
private static final long serialVersionUID = -2548612391437480321L; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Empty comment blocks can be removed
private static final long serialVersionUID = -2548612391437480321L; | ||
|
||
public OAuthException() { | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
empty line
/** | ||
* | ||
*/ | ||
private static final long serialVersionUID = -7407238718258981852L; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
empty javadoc
|
||
/** | ||
* Resource Owner Password Credentials (real users' login name) | ||
* {@see https://tools.ietf.org/html/rfc6749#section-1.3.3} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
no braces
private String clientId; | ||
|
||
/** | ||
* Client secret {@see https://tools.ietf.org/html/rfc6749#section-2.2} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
no braces
/** | ||
* | ||
*/ | ||
private static final long serialVersionUID = -7394989068336468235L; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
empty javadoc
* This is for authorization server that uses basic authentication | ||
* | ||
*/ | ||
private boolean useBasicAuthentication = false; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
no need to initialize
* @author Gary Tse - initial contribution | ||
* | ||
*/ | ||
public interface TestAgent { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since this interface is not part of public API, you can remove it and expose the implementation as a DS Component without any service interface.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is used by ConsoleOAuthCommandExtension; refrencing both of the ResourceOwnerTestAgent and AuthorizationCodeTestAgent.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can have an interface but it is not necessary. You can expose the implementations as @Component(service = ResourceOwnerTestAgent.class)
and @Component(service = AuthorizationCodeTestAgent.class)
. Since the consumers reside in the same bundle, you don't need a service interface.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thx for suggestion. If I use (service = ResourceOwnerTestAgent.class)/ (service = AuthorizationCodeTestAgent.class), do I end up only with the public methods from the 2 classes? I mean, the meat is in the abstract super class TestAgent/ AbstractTestAgent
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, only the public methods will be accessible if you are accessing the DS Component from a different package, otherwise you can also access the package private methods if the consumer is in the same package as the DS Components.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As discussed, leave it as it is
return secretKey; | ||
} | ||
|
||
private static class ConfigurationAdminMock implements ConfigurationAdmin { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of your own custom mock, you can use Mockito which, I believe, already exists in ESH
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thx for suggestion.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Switched; see next commit.
|
||
} | ||
|
||
private static class ConfigurationMock implements Configuration { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of your own custom mock, you can use Mockito which, I believe, already exists in ESH
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thx for suggestion.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Plan to switch to Mockito?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Switched to Mockito, see next commit.
source.. = src/main/java/ | ||
bin.includes = META-INF/,\ | ||
.,\ | ||
OSGI-INF/org.eclipse.smarthome.auth.oauth2client.internal.OAuthFactoryImpl.xml,\ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Only OSGI-INF/
will suffice
* @author Gary Tse - Initial Contribution | ||
* | ||
*/ | ||
@Component(property = { "CIPHER_TARGET=org.eclipse.smarthome.auth.oauth2client.internal.cipher.SymmetricKeyCipher" }) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You don't need the curly braces since it can be used for multiple properties.
} | ||
} | ||
} catch (InterruptedException e) { | ||
// if lock is not acquired within the timeout or thread is interruted |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thread.currentThread.interrupt()
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
InterruptedExceptions should never be ignored in the code, and simply logging the exception counts in this case as "ignoring". The throwing of the InterruptedException clears the interrupted state of the Thread, so if the exception is not handled properly the fact that the thread was interrupted will be lost. Instead, InterruptedExceptions should either be rethrown - immediately or after cleaning up the method's state - or the thread should be re-interrupted by calling Thread.interrupt() even if this is supposed to be a single-threaded application. Any other course of action risks delaying thread shutdown and loses the information that the thread was interrupted - probably without finishing its task.
Similarly, the ThreadDeath exception should also be propagated. According to its JavaDoc:
If ThreadDeath is caught by a method, it is important that it be rethrown so that the thread actually dies.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for this contribution, this was quite some work!
Please find some comments below.
org.junit;resolution:=optional, | ||
org.osgi.framework, | ||
org.osgi.service.cm, | ||
org.osgi.service.component.annotations;resolution:=optional, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
please remove, this import is not needed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have moved junit tests here, so it should be needed. As for framework/ cm/ annotations, they are used by the test agent.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am only talking about "org.osgi.service.component.annotations". This is not needed as the IDE & Tycho provide that already.
org.eclipse.smarthome.io.console, | ||
org.eclipse.smarthome.io.console.extensions, | ||
org.hamcrest;resolution:=optional, | ||
org.json, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This does not seem to be used.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Used by ConsoleOAuthCommandExtension class. The whole oauth2client.test bundle is not just junit-unit test. It acts like demo + integration + unit tests. The Console part allows the oauth client to be created/ used/ closed/ re-loaded by the console commands. See README.md
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was referring to "org.json".
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note that the comments are put UNDER the commented line by Github, not above it.
|
||
public ConsoleOAuthCommandExtension() { | ||
super("oauth", "Test of oauth client with console. Available test agent: {Code, ResourceOwner}.\n" | ||
+ "The commands in oauth requires oauth provider data inputted in configuration admin."); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
typo: inputted -> input or put in
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
corrected grammer: "The commands in oauth requires oauth provider data to be inputted in configuration admin."
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"inputted" is no English word.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks ok with Cambridge dict -- https://dictionary.cambridge.org/dictionary/english/inputted
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, nevermind then - this surprises me and it looks weird to me (being derived from the verb "put"...)
|
||
@Override | ||
public boolean equals(Object thatAuthTokenObj) { | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
remove empty line
* This is the service factory to produce a OAuth2 service client that authenticates using OAUTH2. | ||
* As this is a service factory pattern, thus the OAuthe2 service client is not shared between bundles. | ||
* | ||
* The basic uses of this OAuthClient is as follows: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
typo: are as follows
PersistedParams params = gson.fromJson(value, PersistedParams.class); | ||
return params; | ||
} catch (Exception e) { | ||
logger.error("Unable to deserialize json {}, discarding PersistedParams", value); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same as above
LocalDateTime lastUsedDate = gson.fromJson(value, LocalDateTime.class); | ||
return lastUsedDate; | ||
} catch (Exception e) { | ||
logger.info("Unable to deserialize json {}, reset LocalDateTime to now", value); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
consider json format in statement
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i wish to avoid complications if the json itself cannot even be parsed for whatever reason.
storageLock.lock(); | ||
try { | ||
if (_storage == null) { | ||
throw new RuntimeException(EXCEPTION_STORAGE); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
do not throw RuntimeException
storageLock.lock(); | ||
try { | ||
if (_storage == null) { | ||
throw new RuntimeException(EXCEPTION_STORAGE); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
do not throw RuntimeException
if (_storage == null) { | ||
throw new RuntimeException(EXCEPTION_STORAGE); | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
remove empty line
* @param oAuthStoreHandler | ||
*/ | ||
@Reference | ||
protected void setoAuthStoreHandler(OAuthStoreHandler oAuthStoreHandler) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
rename to setOAuthStoreHandler
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch; this was generated by eclipse !
this.oAuthStoreHandler = oAuthStoreHandler; | ||
} | ||
|
||
protected void unsetoAuthStoreHandler(OAuthStoreHandler oAuthStoreHandler) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
rename to unsetOAuthStoreHandler
Hey @garytse, are you aware that Travis failed with test compilation errors and that the IP validation failed due to merge commits in the branch? Please fix those two issues and I'll do a final review - thanks! |
@garytse As mentioned in #5142 (comment), please never do merge commits! Instead, rebase your branch on the latest master in order to have a clean PR. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks @garytse, I have done a final review and left some comments - please let me know, if anything is not clear or does not make sense to you.
</buildCommand> | ||
</buildSpec> | ||
<natures> | ||
<nature>org.eclipse.m2e.core.maven2Nature</nature> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You should not have m2e nature on any project.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed, sorry about that
@@ -0,0 +1,106 @@ | |||
eclipse.preferences.version=1 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There should be no need for project specific settings, so I'd hope you can remove this file.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
file removed.
@@ -0,0 +1,28 @@ | |||
Manifest-Version: 1.0 | |||
Bundle-ManifestVersion: 2 | |||
Bundle-Name: org.eclipse.smarthome.auth.oauth2client.test |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be something like "Eclipse SmartHome OAuth2Client Tests"
Bundle-Version: 0.10.0.qualifier | ||
Bundle-Vendor: Eclipse.org/SmartHome | ||
Bundle-RequiredExecutionEnvironment: JavaSE-1.8 | ||
Export-Package: org.eclipse.smarthome.auth.oauth2client.test;x-internal:=true, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why are those packages exported?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see; I have misunderstood the meaning of x-internal.
## Try these on the OSGI console: | ||
|
||
|
||
smarthome.oauth Code cleanupEverything |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In the (ESH default) console, the commands are smarthome oauth...
, so the doc should use that format.
protected static final int ACCESS_TOKEN_CACHE_SIZE = 50; | ||
|
||
private static final String STORE_NAME = "StorageHandler.For.OAuthClientService"; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
remove the empty lines between the message constants
private class StorageFacade implements AutoCloseable { | ||
|
||
// Unusual variable name starting with underscore, _storage. | ||
// This way, it cannot be confused with other storage variables locally in the enclosing class. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
And obviously, you should also remove the comment.
} | ||
|
||
public void removeByHandle(String handle) { | ||
logger.info("Removing handle {} from storage", handle); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
reduce to DEBUG
@Override | ||
public void remove(@NonNull String handle) { | ||
storageFacade.removeByHandle(handle); | ||
// allHandles.remove(handle); // done by storage facade |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
line should be removed
if (allHandles.remove(handle)) { // entry exists and successfully removed | ||
if (storage == null) { | ||
// just log the error and let it be, do not throw exception | ||
logger.warn(EXCEPTION_STORAGE); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This method is called for every handle - you wouldn't want to have so many similar WARN messages in the log file; the are not helpful. You hence should decide whether you consider this situation an illegal state (then better throw an exception to the caller) or a valid situation (then there is no need for any log message).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well spotted. throwing IllegalStateException is consistent with the logic.
Since the change is quite a lot, I will retest the whole thing again. Will update here once completed. |
|
||
/** | ||
* Use case 7 - get access token response. The tokens may have been retrieved previously through Use cases: 1d, 2, | ||
* 3, | ||
* 4, 6. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
please remove the superfluous line break.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just a few small typos and Javadoc issues that I found when looking on your latest commit.
Besides this, all looks good to me. So please let me know once your testing was successful and you have updated the remaining things - we should be good to merge then!
* | ||
* @param handle the handle to the oauth service | ||
* @return the oauth service, or null of the handle does not exist | ||
* @throws OAuthException if the handles does not exist |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Typo: "handles" -> "handle"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This actually contradicts the null return value which states "null of the handle does not exist"
* Gets the oauth service for a given handle | ||
* | ||
* @param handle the handle to the oauth service | ||
* @return the oauth service, or null of the handle does not exist |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
typo: of -> if
* @return An authorization URL during the Authorization Code Grant with http request parameters filled in. | ||
* e.g Produces an URL string like this: | ||
* https://oauth.provider?response_type=code&client_id=myClientId&redirect_uri=redirectURI&scope=myScope&state=mySecureRandomState | ||
*/ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"throws" documentation is missing
@Override | ||
public List<String> getUsages() { | ||
return Arrays.asList( | ||
buildCommandUsage("<agent> create","create an oauth client. Agent:={Code | ResourceOwner}"), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, I only saw now the Agent:={Code | ResourceOwner}
. Not too readable, but ok...
private final Set<String> allHandles = new HashSet<>(); // must be initialized | ||
|
||
// gets replaced if Store becomes available. storageFacade handles all the times when | ||
// the actual storage becomes unavilable and locking issues. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
typo: unavilable
Testing completed. Many thanks for the comprehensive review and recommendations! I have learnt a lot. |
Perfect, thanks! |
Also-by: Kai Kreuzer <kai@openhab.org> Also-by: Michael Bock <bockm@telekom.de> Signed-off-by: Gary Tse <gary.tse@telekom.de>
I have realized that the class |
This pull request has been mentioned on openHAB Community. There might be relevant details there: https://community.openhab.org/t/setup-your-own-openhab-cloud-myopenhab-server-instance/24716/111 |
@garytse Have you seen my comment? |
Support getting access token by username password, by authorization code.
Support refresh token
Support caching
No 3rd party library needed
Accounts migration support to be added EDIT: added now