I created a contract and deposited some ERC20 tokens to there.
Is there a way to take to token out form the contract to my wallet?
I also want to know how to approve from the contract to other one wallet.
You need to implement a custom function in your contract that invokes the transfer() function of the token contract.
pragma solidity ^0.8;
interface IERC20 {
function transfer(address to, uint256 amount) external returns (bool);
}
contract MyContract {
address owner = address(0x123);
function withdrawToken(address tokenContract, uint256 amount) external {
// send `amount` of tokens
// from the balance of this contract
// to the `owner` address
IERC20(tokenContract).transfer(owner, amount);
}
}
Related
We're creating a small Blazor app which accesses a 3rd party api which we have no control over. The API is secured using OAuth with a client_id and client_secret on a machine to machine basis. There is no authentication from the user.
Initially we hit the token endpoint with the id and secret and it returns a token with an expiry date and time. Currently we just repeat the initial token request before every call to the api so that the token is always brand new and has never expired.
Is this practice accepted or should I be storing the bearer token and it's expiration date and time somewhere secure on the client to check the expiration before requesting a new token?
I'm conscious that if the app is widely used internally at our business we could start to reach the api usage limits, but also, if we store it locally on the client, could I mistakenly leave us vulnerable to XSS attacks or similar.
I'm looking for best practice guidance really, and, if the advice is to store the token and check against expiry, where and how should I be storing the token securely?
I found a nice solution at:
https://referbruv.com/blog/using-imemorycache-for-token-caching-in-an-aspnet-core-application/
The author gives an excellent demonstration of how to use IMemoryCache for my exact scenario. I implement a Token Service which checks the expiry of the cache item. If it's in date, I just used the cached token. If the token has expired, I fetch a new token from the API.
public class TokenService : ITokenService
{
private readonly IApiAccountService _apiAccountService;
private readonly IMemoryCache _cache;
public TokenService(IMemoryCache cache, IApiAccountService apiAccountService)
{
_cache = cache;
_apiAccountService = apiAccountService;
}
public async Task<string> FetchTokenAsync()
{
string token;
if (!_cache.TryGetValue("Token", out token))
{
var authResult = await _apiAccountService.GetToken();
var options = new MemoryCacheEntryOptions().SetAbsoluteExpiration(TimeSpan.FromSeconds((authResult.expires_at - DateTime.Now).TotalSeconds));
_cache.Set("Token", authResult.access_token, options);
token = authResult.access_token;
}
return token;
}
}
Then, when calling my API I just call the Token Service:
private readonly ITokenService _tokenService;
public ApiService(HttpClient httpClient, IConfiguration configuration, ITokenService tokenService)
{
_httpClient = httpClient;
_configuration = configuration;
_tokenService = tokenService;
}
...
private async Task<List<T>> FetchListAsync<T>(string uri)
{
_httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", await _tokenService.FetchTokenAsync());
var response = await _httpClient.GetAsync(uri);
response.EnsureSuccessStatusCode();
using var responseStream = await
response.Content.ReadAsStreamAsync();
var reader = new StreamReader(responseStream).ReadToEnd();
var responseObject = JsonConvert.DeserializeObject<List<T>>(reader);
return responseObject;
}
// __ Mapping __
mapping (address => uint) approvedUsers;
// __ Function to add addresses to the mapping___
function _addApprover(address _approver, uint _i) public{
approvedUsers[_approver] += approvedUsers[_i];
}
// ___ user from mapping checked and if true then the rate can be change, else not_
function pricing(address _user, uint _rate) public{
require(approvedUsers[_user] == approvedUsers,"User not in the approvers list");
rate = _rate * (10 ** uint256(decimals())); }
I think you want authenticate some addresses to change the rate and other addresses are not able to do.
To do so, you should (There are other ways but this is easier) do this:
//First you declare owner to have access to approve or disapprove users
address owner;
//Then you declare mapping
mapping(address=>bool) approvedUsers;
//Automatically all addresses return false so no one has access to it.
//In constructor, you specify the owner
constructor(){
owner = msg.sender
}
//By using msg.sender, contract who deployed contract will be owner.
//A modify to make some functions just callable by owner
modifier isOwner(){
require(msg.sender == owner, "Access denied");
_;
}
//Now function to approve and disapprove users
function _addApprover(address _approver) public isOwner{
approvedUsers[_approver] = true;
function _removeApprovedUser(address _disapprover) public isOwner{
approvedUsers[_disapprover] = false;
//Now change rating function
function pricing(uint _rate) public{
require(approvedUsers[msg.sender],"User not in the approvers list");
//Because approvedUsers mapping returns a bool, you do not need to compare it and if it is true,
//user have access to change and if it is false user does not have access to change it
rate = _rate * (10 ** uint256(decimals()));
}
The JHipster OAuth2/OIDC default configuration expects the "groups' to be found in the idToken. Can anyone explain how to read the "groups" from the access token instead?
Here are the changes made to retrieve the user's groups / granted authorities from the access token.
Note that for my case the Access Token (JSON) that the auth code is exchanged for contains an "access_token" field as a peer to the idToken. The "access_token" field is an ID or reference to the actual access token with the user's groups. An extra http request is needed to retrieve that "actual" access token.
For Okta the access token is a JWT similar to the idToken so if for some reason you need to configure Okta to add the groups to the access token instead of the idToken you will find them there.
Solution was based in this Spring doc:
Delegation-based strategy with OAuth2UserService
In your WebSecurityConfigurerAdapter class edit your oauth2Login config:
.oauth2Login().userInfoEndpoint().oidcUserService(this.oidcUserService());
Then create the custom oidcUserService():
private OAuth2UserService<OidcUserRequest, OidcUser> oidcUserService() {
final OidcUserService delegate = new OidcUserService();
return (userRequest) -> {
// Delegate to the default implementation for loading a user
OidcUser oidcUser = delegate.loadUser(userRequest);
// The access token will be a reference to the actual token
// ( for Okta this would be the actual JWT access token )
String accessTokenRef = userRequest.getAccessToken().getTokenValue();
// Call the end point to get the actual access_token
// ( httpClient is just a RestTemplate impl w/the required configs )
String[] groups = httpClient.fetchGroups(accessTokenRef);
// Create the GrantedAuthority objs & add to mappedAuthorities set
Set<GrantedAuthority> mappedAuthorities = new HashSet<>();
for (String group: groups) {
mappedAuthorities.add(new SimpleGrantedAuthority(group));
}
// Create a copy of oidcUser but use the mappedAuthorities instead
oidcUser = new DefaultOidcUser(mappedAuthorities, oidcUser.getIdToken(), oidcUser.getUserInfo());
return oidcUser;
};
}
If you are using JHipster there will be a GrantedAuthoritiesMapper that will need to be updated to map the authorities passed in directly to your application roles rather than reading them from the idToken. Something like:
#Bean
public GrantedAuthoritiesMapper userAuthoritiesMapper() {
return (authorities) -> {
Set<GrantedAuthority> mappedAuthorities = new HashSet<>();
Collection<String> roles = new HashSet();
authorities.forEach(authority -> {
roles.add(authority.getAuthority());
});
List<GrantedAuthority> list = SecurityUtils.mapRolesToGrantedAuthorities(roles);
mappedAuthorities = new HashSet<GrantedAuthority>(list);
return mappedAuthorities;
};
}
There are likely some other ways to do this and I would be happy to hear any advice.
Thanks to the commenters for their help.
For the time being I use a test account in Twilio, but I hope that this has no relevance regarding my question.
As my firs experimental step towards Twilio, I'm testing the client-quickstart-csharp-1.4 package on Visual Studio 2017 on Windows.
Outgoing calls work fine to my verified phone, but I have problems with incoming calls. When I make a call from a real phone to my Twilio phonenumber, then my code in VoiceController.cs doesn't run (doesn't hit any breakpoint) and I hear a voice message about that I should reconfigure something my application (but I don't understand, what). In contrast of this, when I make a call from my TwiMLApp config page, pressing the red Call button (see picture),
then my code stops at the breakpoints, and says the text I wrote in the argumet of response.Say().
My questions:
Why does the call work differently from a real phone then from my
TwiMLApp config page?
How can I achieve my code run (i.e. say the text I wrote in the code) also when I make a call from a real phone?
How Can I achieve a real, live voice dialogue between the caller phone and my computer's speaker and microphone at incoming calls (similarly to
the outgoing calls)?
Remark 1.
Both outgoing an incoming calls work fine in Agile CRM using the Twilio widget for voice calls. But for the time of my experiments I've removed this widget (and also the "Agile CRM Twilio Saga" TwiML App from Twilio), to avoid the interferences between the different applications.
Remark 2.
Perhaps I should configure something with this screen (the screenshot found here), but I don't find this page on my twilio portal.
Instead of this, I have a page like this:
But I don't know what to change here to make my program work.
It seems that this application is designed
to manage outgoing calls (to a real phone, or to an other client of this
application) and
accept calls from the web (from an another client,
or from the TwiML App setting page, seen on the first screenshot on the o.p.), but not from a real phone.
Every (outgoing or incoming) call falls into the Index() method of the VoiceController class. This method tries to find out whether a call is incoming or outgoing.
In the case of on outgoing call, the To property of the request parameter of this method is a phonenumber, while at an incoming call from the web is a string (a username), or null (when the call comes from the TwiML App setting page). This justifies the if-else structure in the original code (extended just my remarks starting with (mma))
public ActionResult Index(VoiceRequest request)
{
var callerId = ConfigurationManager.AppSettings["TwilioCallerId"];
var response = new TwilioResponse();
if (!string.IsNullOrEmpty(request.To))
{
// wrap the phone number or client name in the appropriate TwiML verb
// by checking if the number given has only digits and format symbols
if (Regex.IsMatch(request.To, "^[\\d\\+\\-\\(\\) ]+$")) //(mma) supposed to be an outgoing call
{
response.Dial(new Number(request.To), new { callerId });
}
else //(mma) a call from one client to antorher
{
response.Dial(new Client(request.To), new { callerId });
}
}
else //(mma) incoming call from the TwiML App setting page
{
response.Say("Thanks for calling!");
}
return TwiML(response);
Question 3. can be separated into the following two parts:
If at an incoming call we want to establish a real connection with a pre-specified client (say calledUser) instead of reading out the "Thanks for calling!" message, we should replace response.Say("Thanks for calling!"); by response.Dial(cl, new { request.From }); where cl = new Client(calledUser); We can put the value of calledUser into our Local.config, so we can read it from there: var calledUser = ConfigurationManager.AppSettings["calledUser"];
If we want to accept a call from a real phone, then we should recognize this situation. This is exactly when request.To == callerId( = our Twilio phononumber) , so we must split the first condition according this. The new branch will call the pre-specified user.
Putting these together, our new code in VoiceController.cs will look like this:
public ActionResult Index(VoiceRequest request)
{
var callerId = ConfigurationManager.AppSettings["TwilioCallerId"];
var calledUser = ConfigurationManager.AppSettings["calledUser"];
var response = new TwilioResponse();
if (!string.IsNullOrEmpty(request.To))
{
// wrap the phone number or client name in the appropriate TwiML verb
// by checking if the number given has only digits and format symbols
if (Regex.IsMatch(request.To, "^[\\d\\+\\-\\(\\) ]+$"))
{
if (request.To != callerId) //(mma) supposed to be an outgoing call
{
response.Dial(new Number(request.To), new { callerId });
}
else //(mma) supposed to be an incoming call from a real phone
{
var cl = new Client(calledUser);
response.Dial(cl, new { request.From });
}
}
else //(mma) a call from one client to antorher
{
response.Dial(new Client(request.To), new { request.From });
}
}
else //(mma) incoming call from the TwiML App setting page
{
var cl = new Client(calledUser);
response.Dial(cl, new { request.From });
}
return TwiML(response);
}
Of course, if we want to accept a call, then we should start a client with the pre-defined username (calledUser). In order to do this, we can introduce a new Url parameter User, put its value into TempData["User"] by the HomeController and change the var identity = Internet.UserName().AlphanumericOnly(); line in the TokenController.cs to var identity = TempData["User"] == null ? Internet.UserName().AlphanumericOnly() : TempData["User"].ToString();
So, our new HomeController and TokenController look like this:
public class HomeController : Controller
{
public ActionResult Index(string user)
{
TempData["User"] = user;
return View();
}
}
and this:
public class TokenController : Controller
{
// GET: /token
public ActionResult Index()
{
// Load Twilio configuration from Web.config
var accountSid = ConfigurationManager.AppSettings["TwilioAccountSid"];
var authToken = ConfigurationManager.AppSettings["TwilioAuthToken"];
var appSid = ConfigurationManager.AppSettings["TwilioTwimlAppSid"];
// Create a random identity for the client
var identity = TempData["User"] == null ? Internet.UserName().AlphanumericOnly() : TempData["User"].ToString();
// Create an Access Token generator
var capability = new TwilioCapability(accountSid, authToken);
capability.AllowClientOutgoing(appSid);
capability.AllowClientIncoming(identity);
var token = capability.GenerateToken();
return Json(new
{
identity,
token
}, JsonRequestBehavior.AllowGet);
}
}
And, of course, our Local.config file should contain such a line:
<add key="calledUser" value="TheNameOfThePreDefinedUser" />
Console Application - C# .Net 4.6
Dedicated Admin user - I can't have it prompt every time for a login - must run unattended as a native commandline/console application.
I am simply trying to get bearer token to send along with the Graph SDK calls.
I get a token (the same one every time) but am told it's expired. Here is the message:
Access Token Expired, Use Access & Refresh Tokens to Validate
Since this is a console application I do not know how I can get/keep the access and refresh tokens to do this.
FYI: Earlier effort I followed the steps Getting Access Without a User: https://developer.microsoft.com/en-us/graph/docs/concepts/auth_v2_service I could not get past the simple Token HTTP request on that page: unauthorized.
This is my latest effort. Any help would be welcome:
using Microsoft.Graph;
using Microsoft.Identity.Client;
public static async Task<string> GetTokenForAppAsync()
{
if (TokenForApplication == null || TokenForApplicationExpiration <= DateTimeOffset.UtcNow.AddMinutes(5))
{
TokenCacheUser = null;
TokenCacheApplication = null;
ConfidentialClientApplication cl = new ConfidentialClientApplication(Settings.AuthClientId,
returnUrl,
new ClientCredential(Settings.AuthClientSecret),
TokenCacheUser,
TokenCacheApplication);
AuthenticationResult authResult = cl.AcquireTokenForClientAsync(new string[] { "https://graph.microsoft.com/.default" }, true).Result;
TokenForApplication = authResult.AccessToken;
Console.WriteLine(authResult.AccessToken);
}
return TokenForApplication;
}
I am open to any solutions which utilize the MS Graph and Identity Libs.
graph_authentication_example
This is an example of token based authentication for a console application. The application must be run at least one time at which you will be prompted to signin but once that is complete an authentication token is stored on the machine the application runs from.
I run a console application as a task from our server and access the Graph API to get various ActiveDirectory data sets using the Graph Endpoints - Typically I need to login once published and then it runs afterwards - this is in the testing phase just now but seems to work well.
Dependencies:
Must have an Azure Active Directory user which will be used for the login and subsequent authentication. Everything happens in the context of this user.
The following Nuget packages are used:
Microsoft.Graph >= v1.6.2
Microsoft.Graph.Core >= v1.6.2
Microsoft.Identity.Client >= v1.1.0 preview
Microsoft.IdentityModel.Clients.ActiveDirectory >= v3.17.1
Newtonsoft.Json >= v1.0.3
System.Net.Http >= v4.3.3
System.Security.Cryptography.Algorithms >= v4.3.0
System.Security.Cryptography.Encoding >= v4.3.0
System.Security.Cryptography.Primitives >= v4.3.0
You must create an application here [https://apps.dev.microsoft.com/] under same user created above, this will give you your client/app id.
You can see Graph in action here [https://developer.microsoft.com/en-us/graph/graph-explorer/] and login with the user created above to test against your own Azure Active Directory.
Settings
I used a .ini file for storing settings but the values are valid, comments in .ini style - note that there are {name} style text in certain entries, those are for string replacement.
You will see Settings.SomeName - that maps to the following:
[Endpoint]
; we don't want v1.0 because of our needs but it is valid
GraphVersion = beta ; v1.0 or beta
; Common Graph endpoint - we sub version
GraphEndpoint = https://graph.microsoft.com/{version}
[Auth]
; authentication uri
Uri = https://login.microsoftonline.com/{tenant}/oauth2/v2.0/token
; authority uri
Authority = https://login.microsoftonline.com/{tenant}
; if we need to login or re-login
RedirectUri = https%3A%2F%2Flogin.microsoftonline.com%2Fcommon%2Foauth2%2Fnativeclient
; you may have a GUID style tenant but 'common' worked fine since it auth's back to Azure anyway
Tenant = common
; the scopes we needed with Graph, yours may vary
Scopes = { User.ReadBasic.All, User.Read.All, User.ReadWrite.All, Directory.AccessAsUser.All, Directory.Read.All, Directory.ReadWrite.All, Group.ReadWrite.All }
; the id of your azure application - guid
ClientId = xxxx###-2##8-4##9-b##1-ec#########8f2
GrantType = client_credentials
Code Snippets
I tried to include complete functions and indicate separation by indicating which files they come from. These are the main parts for token authentication - mostly code complete with exception to 'private' code.
Starting point: Let's say that in my Program.cs I have a call to the following function, everything flows from here for authentication:
// we are just getting a group by id - CreateAuthenticatedClient() is called before every call to Graph
public static async Task<Group> GetGroupAsync(string groupId)
{
var graphClient = AuthenticationHelper.CreateAuthenticatedClient();
try
{
var group = await graphClient.Groups[groupId].Request().GetAsync();
if (group == null) return null;
return group;
}
catch (ServiceException e)
{
ConsoleHelper.WriteException($"GetGroupAsync.{ServiceErrorString(e)}");
return null;
}
}
AuthenticationHelper.cs - complete class
public class AuthenticationHelper
{
public static string TokenForUser = null;
public static DateTimeOffset TokenForUserExpiration;
// this is the 'magic' where we get the user cache
public static PublicClientApplication IdentityClientApp = new PublicClientApplication(Settings.AuthClientId, Settings.AuthAuthority, TokenCacheHelper.GetUserCache());
private static GraphServiceClient graphClient = null;
// Get an access token for the given context and resourceId. An attempt is first made to
// acquire the token silently. If that fails, then we try to acquire the token by prompting the user.
public static GraphServiceClient CreateAuthenticatedClient()
{
if (graphClient == null)
{
try
{
graphClient = new GraphServiceClient(
Settings.GraphEndpoint,
new DelegateAuthenticationProvider(
async (requestMessage) =>
{
var token = await GetTokenForUserAsync();
requestMessage.Headers.Authorization = new AuthenticationHeaderValue("bearer", token);
requestMessage.Headers.Add("azure-graph-test", "manage group membership");
}));
return graphClient;
}
catch (ServiceException sex)
{
Console.WriteLine($"Could not create a graph client service: {sex.Message}");
}
catch (Exception ex)
{
Console.WriteLine($"Could not create a graph client: {ex.Message}");
}
}
return graphClient;
}
/// <summary>
/// get Token for User
/// </summary>
public static async Task<string> GetTokenForUserAsync()
{
if (TokenForUser == null || TokenForUserExpiration <= DateTimeOffset.UtcNow.AddMinutes(5))
{
AuthenticationResult authResult;
try
{
authResult = await IdentityClientApp.AcquireTokenSilentAsync(Settings.AuthScopes, IdentityClientApp.Users.FirstOrDefault());
TokenForUser = authResult.AccessToken;
}
catch (Exception)
{
if (TokenForUser == null || TokenForUserExpiration <= DateTimeOffset.UtcNow.AddMinutes(5))
{
authResult = await IdentityClientApp.AcquireTokenAsync(Settings.AuthScopes);
TokenForUser = authResult.AccessToken;
TokenForUserExpiration = authResult.ExpiresOn;
}
}
}
return TokenForUser;
}
}
TokenCacheHelper.cs - this is a microsoft class that is key to getting/setting the token cache
// Copyright (c) Microsoft Corporation.
// All rights reserved.
// This code is licensed under the MIT License.
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files(the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions :
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
static class TokenCacheHelper
{
/// <summary>
/// Get the user token cache
/// </summary>
public static TokenCache GetUserCache()
{
if (usertokenCache == null)
{
usertokenCache = new TokenCache();
usertokenCache.SetBeforeAccess(BeforeAccessNotification);
usertokenCache.SetAfterAccess(AfterAccessNotification);
}
return usertokenCache;
}
static TokenCache usertokenCache;
/// <summary>
/// Path to the token cache
/// </summary>
public static string CacheFilePath = System.Reflection.Assembly.GetExecutingAssembly().Location + "msalcache.txt";
private static readonly object FileLock = new object();
public static void BeforeAccessNotification(TokenCacheNotificationArgs args)
{
lock (FileLock)
{
args.TokenCache.Deserialize(File.Exists(CacheFilePath)
? File.ReadAllBytes(CacheFilePath)
: null);
}
}
public static void AfterAccessNotification(TokenCacheNotificationArgs args)
{
// if the access operation resulted in a cache update
if (args.TokenCache.HasStateChanged)
{
lock (FileLock)
{
// reflect changes in the persistent store
File.WriteAllBytes(CacheFilePath, args.TokenCache.Serialize());
// once the write operationtakes place restore the HasStateChanged bit to filse
args.TokenCache.HasStateChanged = false;
}
}
}
}